-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
dynamic populate with refPath in sub-document #12066
Comments
When I wasn't sure what the issue was, I used a mongoose/lib/helpers/populate/getModelsMapForPopulate.js Lines 231 to 247 in a1d88e5
I realized that the resolved
So I got the documents to be populated in two ways
const subdocPath = options.path.slice(0, options.path.length - schema.path.length - 1);
const vals = mpath.get(subdocPath, doc, lookupLocalFields);
const subdocsBeingPopulated = Array.isArray(vals) ? utils.array.flatten(vals) : (vals ? [vals] : []);
for (const subdoc of subdocsBeingPopulated) {
// !! ^^ This was only passed to the refPath if it was a function
if (typeof refPath === 'function') {
modelNames = new Set();
refPath = refPath.call(subdoc, subdoc, options.path);
modelNamesFromRefPath(refPath, subdoc, options.path, modelSchema, options._queryProjection).forEach(name => modelNames.add(name));
// !! ^^ doc to subdoc
modelNames = Array.from(modelNames);
} else {
modelNames = modelNamesFromRefPath(refPath, subdoc, options.path, modelSchema, options._queryProjection);
// !! ^^ doc to subdoc
}
}
const subdocPath = options.path.slice(0, options.path.length - schema.path.length - 1);
if (typeof refPath === 'function') {
const vals = mpath.get(subdocPath, doc, lookupLocalFields);
const subdocsBeingPopulated = Array.isArray(vals) ?
utils.array.flatten(vals) :
(vals ? [vals] : []);
modelNames = new Set();
for (const subdoc of subdocsBeingPopulated) {
refPath = refPath.call(subdoc, subdoc, options.path);
modelNamesFromRefPath(`${subdocPath}.${refPath}`, doc, options.path, modelSchema, options._queryProjection).forEach(name => modelNames.add(name));
// !! ^^ new path
}
modelNames = Array.from(modelNames);
} else {
modelNames = modelNamesFromRefPath(`${subdocPath}.${refPath}`, doc, options.path, modelSchema, options._queryProjection);
// !! ^^ new path
} |
All the |
Yeah @IslandRhythms. I forgot to make the |
const mongoose = require('mongoose');
const subSchema = new mongoose.Schema({
by: {
type: mongoose.Schema.Types.ObjectId,
refPath: "user_type", // path to model
required: true,
},
user_type: {
type: String,
required: true,
// the `by` field should be populated on one of these models
enum: ["Parent", "Child"],
},
});
const RecordSchema = new mongoose.Schema({
title: {
type: String,
required: true,
},
created: {
type: subSchema,
required: true
},
});
const ParentSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
job: { type: String }
});
const ChildSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
siblings: [mongoose.Schema.ObjectId]
});
const Record = mongoose.model('Record', RecordSchema);
const Parent = mongoose.model('Parent', ParentSchema);
const Child = mongoose.model('Child', ChildSchema);
async function run() {
await mongoose.connect('mongodb://localhost:27017');
await mongoose.connection.dropDatabase();
const [parent, child] = await Promise.all([
Parent.create({ name:"Lionel Messi", job: "Footballer" }),
Child.create({ name: "Thiago Messi" })
]);
await Record.create([
{ title: "Heart of a Lio", created: { by: parent._id, user_type: "Parent" } },
{ title: "My day with Hulk", created: { by: child._id, user_type: "Child" } },
{ title: "How to be the GOAT", created: { by: parent._id, user_type: "Parent" } },
]);
console.log(await Record.find().populate('created.by').lean());
}
run(); |
@iammola unfortunately, const subSchema = new mongoose.Schema({
by: {
type: mongoose.Schema.Types.ObjectId,
refPath: "created.user_type", // <-- add `created.` here
required: true,
},
user_type: {
type: String,
required: true,
// the `by` field should be populated on one of these models
enum: ["Parent", "Child"],
},
}); This is a design decision to make it easier to define a If you prefer to specify the path relative to the subdocument, rather than the path relative to the top-level document, it is easier to use const subSchema = new mongoose.Schema({
by: {
type: mongoose.Schema.Types.ObjectId,
ref: subdoc => subdoc.user_type, // <-- `subdoc` is the subdoc being populated
required: true,
},
user_type: {
type: String,
required: true,
// the `by` field should be populated on one of these models
enum: ["Parent", "Child"],
},
}); |
Prerequisites
Mongoose version
6.4.3
Node.js version
18.4.0
MongoDB server version
5.0
Description
This is most likely a bug, but I'm not sure.
I have a path in my model that is a sub-document, and I want to dynamically populate another path in that sub-document using the
refPath
option.I then query the database for a document and populate the
created.by
field, but the path isn't replaced withnull
or the foreign document.Steps to Reproduce
_id_
and another to specify what model to populate on._id
.Expected Behavior
For the sub-document path to be populated with the dynamically specified model.
The text was updated successfully, but these errors were encountered: