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

Nested populate with nested paths and subdocuments is not working fine #14435

Closed
2 tasks done
Saul9201 opened this issue Mar 14, 2024 · 6 comments · Fixed by #14453
Closed
2 tasks done

Nested populate with nested paths and subdocuments is not working fine #14435

Saul9201 opened this issue Mar 14, 2024 · 6 comments · Fixed by #14453
Labels
confirmed-bug We've confirmed this is a bug in Mongoose and will fix it.
Milestone

Comments

@Saul9201
Copy link

Prerequisites

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

Mongoose version

8.2.1

Node.js version

18.19.1

MongoDB server version

7.0.6

Typescript version (if applicable)

No response

Description

When I try to populate a document with nested paths it is not working correctly. I am getting the error: schema.applyGetters is not a function.

Steps to Reproduce

const mongoose = require('mongoose');

const CodeSchema = new mongoose.Schema({
    code: String,
});

const UserSchema = new mongoose.Schema({
    extras: [
        new mongoose.Schema({
            config: new mongoose.Schema({
                paymentConfiguration: {
                    paymentMethods: [
                        {
                            type: mongoose.Schema.Types.ObjectId,
                            ref: 'Code'
                        }
                    ]
                },
            })
        })
    ],
});

const Code =  mongoose.model('Code', CodeSchema);
const User = mongoose.model('User', UserSchema);

(async () => {
    await mongoose.connect('mongodb://localhost:27017/test');
    const code = new Code({
        code: 'test',
    });
    await code.save();
    const user = await new User({
        extras: [
            {
                config: {
                    paymentConfiguration: {
                        paymentMethods: [code._id]
                    }
                }
            }
        ]
    }).save();

    const result = await User.findOne({_id: user.id}).populate('extras.config.paymentConfiguration.paymentMethods');
    console.log(JSON.stringify(result, null, 2));
    await mongoose.disconnect();
})();

Output:

/projects/mongoose-poc/node_modules/mongoose/lib/document.js:1930
    obj = schema.applyGetters(obj, this);
                 ^

TypeError: schema.applyGetters is not a function
    at Document.get (/projects/mongoose-poc/node_modules/mongoose/lib/document.js:1930:18)
    at Document.populated (/projects/mongoose-poc/node_modules/mongoose/lib/document.js:4530:25)
    at assignVals (/projects/mongoose-poc/node_modules/mongoose/lib/helpers/populate/assignVals.js:184:15)
    at _assign (/projects/mongoose-poc/node_modules/mongoose/lib/model.js:4711:3)
    at _done (/projects/mongoose-poc/node_modules/mongoose/lib/model.js:4521:9)
    at _next (/projects/mongoose-poc/node_modules/mongoose/lib/model.js:4509:7)
    at /projects/mongoose-poc/node_modules/mongoose/lib/model.js:4617:7
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Expected Behavior

It should return the user document with the array extras.config.paymentConfiguration.paymentMethods populated correctly

@vkarpov15 vkarpov15 added this to the 8.2.2 milestone Mar 15, 2024
@vkarpov15 vkarpov15 added the has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue label Mar 15, 2024
@vkarpov15 vkarpov15 modified the milestones: 8.2.2, 8.2.3 Mar 15, 2024
@FaizBShah
Copy link
Contributor

@Saul9201 I've tried debugging this, and what I have found is that the reason the error is coming is because the schema of the path extras.config.paymentConfiguration is just the string nested. Normally, the schemas should be an object, but in this scenario, its nested. And since we are calling schema.applyGetters() in document.js, and a string does not have any function called applyGetters(), that's why its failing

@FaizBShah
Copy link
Contributor

Found the reason from the docs. So apparently, any field which is an object but does not have the type field in Schema is a nested schema. In your case, paymentConfiguration field is nested schema. Now, as you can see in the highlighted para in the doc, the path for the field which is a nested schema is not actually created by Mongoose, and thus it might give error in doing population.

@FaizBShah
Copy link
Contributor

FaizBShah commented Mar 17, 2024

I think yours is a valid use case and it could be implemented by mongoose, but for now you can fix this by converting the paymentConfiguration field into a Schema, or probably populating without using the dotted-string population method.

Personally, I feel the dotted-string approach for valid paths, even if they are inside nested docs, should work correctly.

@Saul9201
Copy link
Author

Thank you very much @FaizBShah, I've also been debugging and reached the same conclusion. A possible workaround is to use a Subdocument instead of Nested Path, as this way the path to the extras.config.paymentConfiguration branch is created:

const UserSchema = new mongoose.Schema({
    extras: [
        new mongoose.Schema({
            config: new mongoose.Schema({
                paymentConfiguration: new mongoose.Schema({
                    paymentMethods: [
                        {
                            type: mongoose.Schema.Types.ObjectId,
                            ref: 'Code'
                        }
                    ]
                }),
            })
        })
    ],
});

But I agree with you, the schema with Nested Path is also a valid schema and should work correctly.

@FaizBShah
Copy link
Contributor

Yupp, btw just to clarify, this is only happening because your extras field is an array. If it were a subdocument, the function would have worked perfectly fine (I've tested it in local, and its working fine). For some reason, mongoose is not able to handle nested documents within an array parent, but otherwise its able to do it. In normal case (i.e. no array parent), the schema is coming to be null in document.js, and its inferring the value from the document's this instance. But in array parent case, the schema is coming to be nested and its failing the function

@FaizBShah
Copy link
Contributor

@Saul9201 Have added a PR which prevents the applyGetters() function from getting called if schemaType is nested - #14443. This won't affect the result of the population of data as that has already been done by the time this function is called.

@vkarpov15 vkarpov15 added confirmed-bug We've confirmed this is a bug in Mongoose and will fix it. and removed has repro script There is a repro script, the Mongoose devs need to confirm that it reproduces the issue labels Mar 20, 2024
vkarpov15 added a commit that referenced this issue Mar 21, 2024
fix(schema): avoid returning string 'nested' as schematype
@vkarpov15 vkarpov15 reopened this Mar 21, 2024
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
3 participants