Skip to content

fix: de-duplicate events returned by generic tag-filter subscriptions#694

Open
Priyanshubhartistm wants to merge 1 commit into
cameri:mainfrom
Priyanshubhartistm:fix/duplicate-events-on-tag-filter-queries
Open

fix: de-duplicate events returned by generic tag-filter subscriptions#694
Priyanshubhartistm wants to merge 1 commit into
cameri:mainfrom
Priyanshubhartistm:fix/duplicate-events-on-tag-filter-queries

Conversation

@Priyanshubhartistm

Copy link
Copy Markdown
Collaborator

Description

EventRepository.findByFilters() left-joins event_tags when a filter contains a generic tag query (#e, #p, #g, etc.) and selects events.* with no DISTINCT or GROUP BY. If an event has more than one event_tags row matching the filter's criteria for the same query - for example a filter of {"#p": ["a", "b"]} matching an event that is tagged with both a and b - the join produces one result row per matching tag row instead of one row per event. Those rows are streamed straight to the subscriber by SubscribeMessageHandler.fetchAndSend(), so the client receives duplicate EVENT messages for the same event within a single subscription.

The tag-query branch of findByFilters() now uses builder.distinct('events.*') instead of builder.select('events.*'), so each stored event is returned at most once regardless of how many tag rows it matches. countByFilters() was already unaffected - it already wraps its result in countDistinct({ count: 'event_id' }).

Related Issue

#693

Motivation and Context

This is a protocol-correctness bug: NIP-01 subscribers expect each matching event once per subscription. Duplicate delivery wastes client bandwidth/processing and can confuse client-side dedup logic that isn't expecting repeats within the same REQ.

How Has This Been Tested?

  • Updated the 11 existing unit tests in test/unit/repositories/event-repository.spec.ts that assert the exact generated SQL for #e, #g, #p, #r, and #d tag filters - they now expect select distinct "events".* instead of select "events".*.
  • Ran the full test/unit/repositories/event-repository.spec.ts suite (62 tests) - all pass, including the countByFilters tests, confirming that code path (already correct via countDistinct) is untouched.
  • Ran pnpm lint, pnpm check:deps, pnpm run build, pnpm run build:check, pnpm run verify:cli:build, pnpm run test:unit (1393 passing), pnpm run test:cli (73 passing), and pnpm run cover:unit - all pass.

Screenshots (if appropriate):

N/A - backend query change only.

Types of changes

  • Non-functional change (docs, style, minor refactor)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my code changes.
  • I added a changeset, or this is docs-only and I added an empty changeset.
  • All new and existing tests passed.

@changeset-bot

changeset-bot Bot commented Jul 18, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 65dd621

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
nostream Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coveralls

Copy link
Copy Markdown
Collaborator

Coverage Status

coverage: 67.648%. remained the same — Priyanshubhartistm:fix/duplicate-events-on-tag-filter-queries into cameri:main

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants