Mongoose填充子子文档

时间:2014-06-25 17:26:32

标签: javascript node.js mongodb mongoose

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

9 个答案:

答案 0 :(得分:74)

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



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




答案 1 :(得分:22)

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

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”版本完成的,因此它是非阻塞的,但通常在所有操作之后,响应中的所有项目不仅填充了注释,而且注释本身具有相关的“用户”的信息。

答案 2 :(得分:7)

简单

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

答案 3 :(得分:7)

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

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

答案 4 :(得分:2)

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

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

])

当我不得不获取同一父级的多个子子文档时,我发现第二种方法(使用数组)更有用。

答案 5 :(得分:2)

我使用这个:

.populate({
            path: 'pathName',
            populate: [
                {
                    path: 'FirstSubPathName',
                    model: 'CorrespondingModel',
                },
                {
                    path: 'OtherSubPathName',
                    model: 'CorrespondingModel',
                },
                {
                    path: 'AnotherSubPathName',
                    model: 'CorrespondingModel',
                },
            ]
        });

这是我发现的更简单的方法。希望对您有所帮助。 :)

答案 6 :(得分:0)

尝试一下它的工作 查找项目并获取与项目相关的填充任务和垂直任务用户查找

db.Project.find()
.populate({
    path: 'task',
    populate: { path: 'user_id'}
})
.exec(async(error,results)=>{

})

答案 7 :(得分:0)

检查以下屏幕截图。这东西就像魅力一样!!! enter image description here

答案 8 :(得分:0)

这对我有用:

即不需要模型

    .populate({
      path: 'filters',
      populate: {
        path: 'tags',
        populate: {
          path: 'votes.user'
        }
      }
    })
    .populate({
      path: 'members'
    })