-
- Notifications
You must be signed in to change notification settings - Fork 3.9k
Description
Prerequisites
- I have written a descriptive issue title
- I have searched existing issues to ensure the bug has not already been reported
Mongoose version
6.3.1
Node.js version
14
MongoDB server version
4.4.0
Description
If you are trying to use the aggregation pipeline to search a Model that has a discriminatorKey, this error is thrown because the discriminatorKey's match phase is automatically injected into the pipeline before the search's match phase.
$match with $text is only allowed as the first pipeline stage
Steps to Reproduce
import { Schema, model } from 'mongoose'; // setup a parent schema with a discriminatorKey const ParentSchema: Schema = new Schema( { title: String, description: String, }, { discriminatorKey: 'partition', } ); // create search index on the title and description fields ParentSchema.index({ partition: 1, title: 'text', description: 'text', }); // create child schema to inherit from parent const ChildSchema: Schema = new Schema( { type: String, }, { discriminatorKey: 'partition', } ); // create models const Parent = model('Parent', ParentSchema); Parent.discriminator('Child', ChildSchema); const Child = model('Child'); (async function () { // insert a child document to search for await Child.create({ title: 'Hello World', description: 'This is a test', type: 'Test', }); // search for child document using the aggregation pipeline await Child.aggregate([ { $match: { partition: 'Child', $text: { $search: 'test', }, }, }, ]); // MongoServerError: $match with $text is only allowed as the first pipeline stage })();Clearly I put $text in the first pipeline stage but mongoose injects its own discriminatorKey match into the pipeline ahead of mine and produces this in mongo:
db.parents.aggregate([ { $match: { partition: 'Child' } }, { $match: { partition: 'Child', $text: { $search: 'test' } } }, ]);If I remove the partition param from my $match, then mongoose's $match is merged into mine and it works:
Child.aggregate([ { $match: { $text: { $search: 'test', }, }, }, ])Produces this in mongo...
db.parents.aggregate([ { $match: { $text: { $search: 'test' }, partition: 'Child' } } ]);Expected Behavior
If the first pipeline stage is a $match, Mongoose should always merge its discriminatorKey params into the first stage instead of inserting an additional $match above it. If the first stage already contains a discriminatorKey param then the auto-generated params from Mongoose should be dropped.