J'ai cette configuration dans ma MongoDB
Articles:
title: String
comments: [] // of objectId's
Commentaires:
user: ObjectId()
item: ObjectId()
comment: String
Voici mon schéma Mongoose:
itemSchema = mongoose.Schema({
title: String,
comments: [{ type: Schema.Types.ObjectId, ref: 'comments' }],
});
Item = mongoose.model('items', itemSchema);
commentSchema = mongoose.Schema({
comment: String,
user: { type: Schema.Types.ObjectId, ref: 'users' },
});
Comment = mongoose.model('comments', commentSchema);
C'est là que je reçois mes articles avec les commentaires:
Item.find({}).populate('comments').exec(function(err, data){
if (err) return handleError(err);
res.json(data);
});
Comment remplir le tableau de commentaires avec son utilisateur respectif? Depuis chaque commentaire a un utilisateur ObjectId ()?
Comme exemple complet d’appel, peupler les objets de résultat:
Item.find({}).populate("comments").exec(function(err,data) {
if (err) return handleError(err);
async.forEach(data,function(item,callback) {
User.populate(item.comments,{ "path": "user" },function(err,output) {
if (err) throw err; // or do something
callback();
});
}, function(err) {
res.json(data);
});
});
L'appel à .populate()
dans le formulaire appelé à partir du modèle prend un document ou un tableau comme premier argument. Ainsi, vous parcourez les résultats renvoyés pour chaque élément et appelez de la sorte pour chaque tableau de commentaires. Le "chemin" indique à la fonction à quoi elle correspond.
Pour cela, la version "async" de forEach est non bloquante, mais généralement après la manipulation, tous les éléments de la réponse sont non seulement renseignés avec des commentaires, mais les commentaires eux-mêmes possèdent les détails "utilisateur" associés.
Une autre façon (plus facile) de le faire:
Item
.find({})
.populate({
path: 'comments',
populate: { path: 'user',
model: 'users' }
})
.exec(function(err, data){
if (err) return handleError(err);
res.json(data);
});
Plus simple
Item
.find({})
.populate({
path: 'comments.user',
model: 'users' }
})
.exec(function(err, data){
if (err) return handleError(err);
res.json(data);
});
Pour ajouter une dernière méthode que les utilisateurs peuvent utiliser pour sélectionner uniquement des champs particuliers dans des sous-documents, vous pouvez utiliser la syntaxe 'select' suivante:
Model.findOne({ _id: 'example' })
.populate({
path: "comments", // 1st level subdoc (get comments)
populate: { // 2nd level subdoc (get users in comments)
path: "user",
select: 'avatar name _id'// space separated (selected fields only)
}
})
.exec((err, res) => {
// etc
});
Pour renseigner un sous-sous-document et à partir de plusieurs schémas
ProjectMetadata.findOne({id:req.params.prjId})
.populate({
path:'tasks',
model:'task_metadata',
populate:{
path:'assigned_to',
model:'users',
select:'name employee_id -_id' // to select fields and remove _id field
}
})
.populate({
path:'client',
model:'client'
})
.populate({
path:'prjct_mgr',
model:'users'
})
.populate({
path:'acc_exec',
model:'users'
})
.populate({
path:'prj_type',
model:'project_type'
}).then ( // .. your thing
ou vous pouvez le faire de la manière suivante ..
ProjectMetadata.findOne({id:req.params.prjId})
.populate(
[{
path:'tasks',
model:TaskMetadata,
populate:[{
path:'assigned_to',
model:User,
select:'name employee_id'
},
{
path:'priority',
model:Priority,
select:'id title'
}],
select:"task_name id code assign_to stage priority_id"
},
{
path:'client',
model:Client,
select:"client_name"
},
{
path:'prjct_mgr',
model:User,
select:"name"
},
{
path:'acc_exec',
model:User,
select:'name employee_id'
},
{
path:'poc',
model:User,
select:'name employee_id'
},
{
path:'prj_type',
model:ProjectType,
select:"type -_id"
}
])
J'ai trouvé la deuxième méthode (d'utiliser un tableau) plus utile lorsque je devais obtenir plusieurs sous-sous-documents du même parent.