【问题标题】:Mongoose populate sub-sub documentMongoose 填充子子文档
【发布时间】:2014-08-16 09:19:40
【问题描述】:

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

这是我与 cmets 一起获得物品的地方:

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

如何使用其各自的用户填充 cmets 数组?既然每条评论都有一个用户ObjectId()?

【问题讨论】:

标签: javascript node.js mongodb mongoose


【解决方案1】:

另一种方法(更简单):

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

【讨论】:

  • 感谢您的回答。你的回答很棒。
  • 顺便说一下,不需要第一次填充
  • 这是在 4 小时的研究中对我有用的独特答案,恭喜! >
  • 更容易并帮助解决我的问题!非常感谢!
【解决方案2】:

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

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() 的调用将文档或数组作为其第一个参数。因此,您循环遍历每个项目的返回结果,并以这种方式在每个“cmets”数组上调用填充。 “路径”告诉函数它匹配的是什么。

这是使用 forEach 的“异步”版本完成的,因此它是非阻塞的,但通常在所有操作之后,响应中的所有项目不仅填充有 cmets,而且 cmets 本身具有相关的“用户”详情。

【讨论】:

  • 这很有帮助。谢谢!
  • @neil Lunn 我遇到了错误。你能帮我解决这个问题吗? async.forEach(data,function(item,callback) { ^ ReferenceError: async is not defined
  • @FarheenP - 使用npm install async 安装它,然后您可以通过var async = require('async'); 包含它。见github.com/caolan/async
【解决方案3】:

更简单

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

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

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

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

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

      【讨论】:

        【解决方案6】:

        我用这个:

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

        这是我发现的更简单的方法。我希望能提供帮助。 :)

        【讨论】:

          【解决方案7】:

          试试看吧 查找项目并获取与项目相关的填充任务和特定任务用户查找

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

          【讨论】:

          • 欢迎来到 SO!尝试格式化您的答案以获得更好的可读性,这将有助于其他人遇到相同的问题。
          【解决方案8】:

          查看下面的屏幕截图。这东西就像魅力一样!

          【讨论】:

          • Please don't post screenshots of text。它们无法被搜索或复制,并且可用性差。相反,将代码作为文本直接粘贴到您的问题中。如果选择它并单击{} 按钮或 Ctrl+K 代码块将缩进四个空格,这将导致其呈现为代码。
          【解决方案9】:

          这对我有用:

          即不需要模型

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

          【讨论】:

            猜你喜欢
            • 2017-01-27
            • 1970-01-01
            • 2017-03-21
            • 2017-06-06
            • 2018-08-16
            • 2019-01-08
            • 1970-01-01
            • 2014-11-20
            • 2020-12-18
            相关资源
            最近更新 更多