web-dev-qa-db-fra.com

Mongoose peupler sous-sous-document

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 ()?

16
iamjonesy

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.

22
Neil Lunn

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);
});

65
Antenka

Plus simple

Item
  .find({})
  .populate({
    path: 'comments.user',
    model: 'users' }
  })
  .exec(function(err, data){
    if (err) return handleError(err);
    res.json(data);
});
7
steampowered

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
     });
7
jacobedawson

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.

1
Yash Ojha