Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to use $in to query a nested discriminator key field together with a field from a child schema #13492

Closed
2 tasks done
juona opened this issue Jun 9, 2023 · 0 comments · Fixed by #13496
Closed
2 tasks done
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Milestone

Comments

@juona
Copy link

juona commented Jun 9, 2023

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Mongoose version

7.2.2

Node.js version

16.19.1

MongoDB server version

5

Typescript version (if applicable)

No response

Description

Forgive me for the complicated issue title - the problem is too specific.

I have a schema with a nested discriminator:

const itemStateFooSchema = new mongoose.Schema({
    fieldFoo: String
});

const itemSchema = new mongoose.Schema({
    state: new mongoose.Schema(
        {
            field: String
        },
        {
            discriminatorKey: "type"
        }
    )
});

itemSchema.path<mongoose.Schema.Types.Subdocument>("state").discriminator("FOO", itemStateFooSchema);

const itemModel = mongoose.model("item", itemSchema);

The following query does not work:

await itemModel.find({
    "state.type": {
        $in: ["FOO"]
    },
    "state.fieldFoo": "test"
});

Mongoose throws an error:

      TypeError: Cannot read properties of undefined (reading 'path')

      68 |         console.log(5);
      69 |
    > 70 |         await itemModel.find({
         |         ^
      71 |             "state.type": {
      72 |                 $in: ["FOO"]
      73 |             },

      at cast (node_modules/mongoose/lib/cast.js:123:17)
      at model.Query.Object.<anonymous>.Query.cast (node_modules/mongoose/lib/query.js:4874:12)
      at model.Query.Object.<anonymous>.Query._castConditions (node_modules/mongoose/lib/query.js:2210:10)
      at model.Query._find (node_modules/mongoose/lib/query.js:2236:8)
      at model.Query.exec (node_modules/mongoose/lib/query.js:4404:28)
      at Object.<anonymous> (src/test/a.test.ts:70:9)

The problem occurs with the specific combination:

  1. the discriminator key is queried using the $in operator;
  2. a field from a child schema is also queried.

This might be reproducible with operators other than $in - I never tried.

The problem does not occur with any of the following queries:

await itemModel.find({
    "state.type": "FOO",
    "state.field": "test"
});

await itemModel.find({
    "state.type": "FOO",
    "state.fieldFoo": "test"
});

await itemModel.find({
    "state.type": {
        $in: "FOO"
    },
    "state.field": "test"
});

await itemModel.find({
    "state.type": "FOO",
    "state.field": {
        $in: ["test"]
    }
});

await itemModel.find({
    "state.type": "FOO",
    "state.fieldFoo": {
        $in: ["test"]
    }
});

This also does not seem to happen if the discriminator is applied to the base schema instead of a nested one, or if there are no discriminators involved at all.

I also tried using strict: false, strictQuery: false - did not help.

Steps to Reproduce

Full code.

const itemStateFooSchema = new mongoose.Schema({
    fieldFoo: String
});

const itemSchema = new mongoose.Schema({
    state: new mongoose.Schema(
        {
            field: String
        },
        {
            discriminatorKey: "type"
        }
    )
});

itemSchema.path<mongoose.Schema.Types.Subdocument>("state").discriminator("FOO", itemStateFooSchema);

const itemModel = mongoose.model("item", itemSchema);

await mongoose.connect(MONGODB_URI);

console.log(0);

await itemModel.find({
    "state.type": "FOO",
    "state.field": "test"
});

console.log(1);

await itemModel.find({
    "state.type": "FOO",
    "state.fieldFoo": "test"
});

console.log(2);

await itemModel.find({
    "state.type": {
        $in: "FOO"
    },
    "state.field": "test"
});

console.log(3);

await itemModel.find({
    "state.type": "FOO",
    "state.field": {
        $in: ["test"]
    }
});

console.log(4);

await itemModel.find({
    "state.type": "FOO",
    "state.fieldFoo": {
        $in: ["test"]
    }
});

console.log(5);

await itemModel.find({
    "state.type": {
        $in: ["FOO"]
    },
    "state.fieldFoo": "test"
});

console.log(6, "this will never log");

Expected Behavior

My understanding is that this query should work:

await itemModel.find({
    "state.type": {
        $in: ["FOO"]
    },
    "state.fieldFoo": "test"
});

It should return all documents where "state.type" is "FOO" and "state.fieldFoo" is "test". Naturally, these will be documents whose "state" conforms to the itemStateFooSchema.

@vkarpov15 vkarpov15 added the confirmed-bug We've confirmed this is a bug in Mongoose and will fix it. label Jun 10, 2023
@vkarpov15 vkarpov15 added this to the 7.2.4 milestone Jun 10, 2023
vkarpov15 added a commit that referenced this issue Jun 12, 2023
fix(query): handle non-string discriminator key values in query
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants