Poblar matriz anidada en mongoose

¿Cómo puedo completar “componentes” en el documento de ejemplo?

{ "__v": 1, "_id": "5252875356f64d6d28000001", "pages": [ { "__v": 1, "_id": "5252875a56f64d6d28000002", "page": { "components": [ "525287a01877a68528000001" ] } } ], "author": "Book Author", "title": "Book Title" } 

Este es mi JS donde recibo el documento de Mongoose:

  Project.findById(id).populate('pages').exec(function(err, project) { res.json(project); }); 

Mongoose 4.5 admite esto

 Project.find(query) .populate({ path: 'pages', populate: { path: 'components', model: 'Component' } }) .exec(function(err, docs) {}); 

Funciona para mi:

  Project.find(query) .lean() .populate({ path: 'pages' }) .exec(function(err, docs) { var options = { path: 'pages.components', model: 'Component' }; if (err) return res.json(500); Project.populate(docs, options, function (err, projects) { res.json(projects); }); }); 

Documentación: Model.populate

Como otros han notado, Mongoose 4 apoya esto. Es muy importante tener en cuenta que también puede recurse más allá de un nivel, si es necesario, aunque no se menciona en los documentos:

 Project.findOne({name: req.query.name}) .populate({ path: 'threads', populate: { path: 'messages' , model: 'Message' , populate: { path: 'user' , model: 'User' } } }) 

Encontré esto muy útil creando un feathersjs before hook para poblar una relación profunda de dos niveles de ref. Los modelos de mongoose simplemente tienen

 tables = new Schema({ .. tableTypesB: { type: Schema.Types.ObjectId, ref: 'tableTypesB' }, .. } tableTypesB = new Schema({ .. tableType: { type: Schema.Types.ObjectId, ref: 'tableTypes' }, .. } 

luego en feathersjs before hook:

 module.exports = function(options = {}) { return function populateTables(hook) { hook.params.query.$populate = { path: 'tableTypesB', populate: { path: 'tableType' } } return Promise.resolve(hook) } } 

Tan simple en comparación con algunos otros métodos que estaba tratando de lograr esto.

Puede llenar múltiples documentos nesteds como este.

  Project.find(query) .populate({ path: 'pages', populate: [{ path: 'components', model: 'Component' },{ path: 'AnotherRef', model: 'AnotherRef', select: 'firstname lastname' }] }) .exec(function(err, docs) {}); 

Usted puede hacer esto usando la agregación $lookup también

 Project.aggregate([ { "$match": { "_id": mongoose.Types.ObjectId(id) } }, { "$lookup": { "from": Pages.collection.name, "let": { "pages": "$pages" }, "pipeline": [ { "$match": { "$expr": { "$in": [ "$_id", "$$pages" ] } } }, { "$lookup": { "from": Component.collection.name, "let": { "components": "$components" }, "pipeline": [ { "$match": { "$expr": { "$in": [ "$_id", "$$components" ] } } }, ], "as": "components" }}, ], "as": "pages" }} ]) 

Eliminar referencia de documentos

 if (err) { return res.json(500); } Project.populate(docs, options, function (err, projects) { res.json(projects); }); 

Esto funcionó para mí.

 if (err) { return res.json(500); } Project.populate(options, function (err, projects) { res.json(projects); });