Skip to content

Model with discriminatorKey throws error in aggregation pipeline when performing a search  #12478

@georgehess

Description

@georgehess

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    confirmed-bugWe've confirmed this is a bug in Mongoose and will fix it.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions