Describe the bug
In src/repositories/event-repository.ts, when a filter contains a generic tag query, the query builder does a leftJoin onto event_tags and selects events.*:
if (isTagQuery) {
builder.leftJoin('event_tags', 'events.event_id', 'event_tags.event_id')
.select('events.*')
}
There is no DISTINCT / GROUP BY on the event id. An event that has multiple rows in event_tags matching the filter criteria (for example a filter of {"#p": ["a", "b"]} matching an event that tags both a and b, or simply an event with several p tags matched by an orWhere) produces one result row per matching tag row. Those rows are streamed straight to the client by SubscribeMessageHandler.fetchAndSend(), so the client receives duplicate EVENT messages for the same event within a single subscription.
To Reproduce
- Store an event that has two
p tags, e.g. ["p","aa..."] and ["p","bb..."].
- Subscribe with
["REQ","sub",{"#p":["aa...","bb..."]}].
- The event is delivered twice.
Expected behavior
Each stored event should be delivered at most once per subscription. The join should be de-duplicated (e.g. .distinct('events.event_id') / a GROUP BY, or an EXISTS/whereIn subquery instead of a join).
Screenshots
N/A
System (please complete the following information):
- OS: Linux
- Platform: Docker
- Version: 3.0.0
Logs
N/A - only observable as duplicate EVENT messages received by a subscribed client for the same event id.
Additional context
This is a different root cause from the NIP-01 default-sort-order issue filed separately against this same file - it is about row multiplication from the tag join, not sort direction. Affects any generic tag filter (#e, #p, #g, #r, #d, etc.) where a single event matches more than one event_tags row for the filter's criteria.
Describe the bug
In
src/repositories/event-repository.ts, when a filter contains a generic tag query, the query builder does aleftJoinontoevent_tagsand selectsevents.*:There is no
DISTINCT/GROUP BYon the event id. An event that has multiple rows inevent_tagsmatching the filter criteria (for example a filter of{"#p": ["a", "b"]}matching an event that tags bothaandb, or simply an event with severalptags matched by anorWhere) produces one result row per matching tag row. Those rows are streamed straight to the client bySubscribeMessageHandler.fetchAndSend(), so the client receives duplicateEVENTmessages for the same event within a single subscription.To Reproduce
ptags, e.g.["p","aa..."]and["p","bb..."].["REQ","sub",{"#p":["aa...","bb..."]}].Expected behavior
Each stored event should be delivered at most once per subscription. The join should be de-duplicated (e.g.
.distinct('events.event_id')/ aGROUP BY, or anEXISTS/whereInsubquery instead of a join).Screenshots
N/A
System (please complete the following information):
Logs
N/A - only observable as duplicate EVENT messages received by a subscribed client for the same event id.
Additional context
This is a different root cause from the NIP-01 default-sort-order issue filed separately against this same file - it is about row multiplication from the tag join, not sort direction. Affects any generic tag filter (
#e,#p,#g,#r,#d, etc.) where a single event matches more than oneevent_tagsrow for the filter's criteria.