diff --git a/package.json b/package.json index d484a908..5a468592 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hawk.api", - "version": "1.5.1", + "version": "1.5.2", "main": "index.ts", "license": "BUSL-1.1", "scripts": { diff --git a/src/models/eventsFactory.js b/src/models/eventsFactory.js index c552bc41..18f0b2e1 100644 --- a/src/models/eventsFactory.js +++ b/src/models/eventsFactory.js @@ -403,6 +403,22 @@ class EventsFactory extends Factory { return { 'event.assignee': String(assignee) }; })(); + /** + * These filters match joined event.* fields, so their $match must run + * after the lookups. With none set, $limit can move before the lookups + * and skip joining rows we'd drop anyway (~8.8s). + * Trim search to match searchFilter's own condition. + */ + const hasContentFilters = + search.trim().length > 0 || + Boolean(release) || + Boolean(assignee) || + Object.keys(matchFilter).length > 0; + + if (!hasContentFilters) { + pipeline.push({ $limit: limit + 1 }); + } + pipeline.push( /** * Left outer join original event on groupHash field @@ -434,21 +450,25 @@ class EventsFactory extends Factory { path: '$repetition', preserveNullAndEmptyArrays: true, }, - }, - { - $match: { - ...matchFilter, - ...searchFilter, - ...releaseFilter, - ...assigneeFilter, - }, - }, - { $limit: limit + 1 }, - { - $unset: 'groupHash', } ); + if (hasContentFilters) { + pipeline.push( + { + $match: { + ...matchFilter, + ...searchFilter, + ...releaseFilter, + ...assigneeFilter, + }, + }, + { $limit: limit + 1 } + ); + } + + pipeline.push({ $unset: 'groupHash' }); + const cursor = this.getCollection(this.TYPES.DAILY_EVENTS).aggregate(pipeline); const result = await cursor.toArray();