首页 文章

Mongoose填充子子文档

提问于
浏览
15

我在MongoDB中有这个设置

项目:

title: String
comments: [] // of objectId's

评论:

user: ObjectId()
item: ObjectId()
comment: String

这是我的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);

这是我得到我的项目和评论的地方:

Item.find({}).populate('comments').exec(function(err, data){
    if (err) return handleError(err);
    res.json(data);
});

如何使用相应的用户填充注释数组?由于每条评论都有一个用户ObjectId()?

5 回答

  • 6

    作为调用结果对象填充的完整示例:

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

    从模型调用的形式对.populate()的调用采用文档或数组作为它的第一个参数 . 因此,您遍历每个项目的返回结果,并在每个"comments"数组上调用此方式填充 . "path"告诉函数它匹配的是什么 .

    这是使用forEach的“async”版本完成的,因此它是非阻塞的,但通常在所有操作之后,响应中的所有项目不仅填充了注释,而且注释本身具有相关的“用户”详细信息 .

  • 63

    还有一种方法(更容易):

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

    更简单

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

    要添加一个人们可能想要用来从子文档中仅选择特定字段的最终方法,您可以使用以下“select”语法:

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

    填充子子文档并从多个模式填充

    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
    

    或者您可以通过以下方式完成..

    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"
        }
    
    ])
    

    当我必须获得同一父节点的多个子子文档时,我发现第二种方法(使用数组)更有用 .

相关问题