【问题标题】:Mongoose populate embedded猫鼬填充嵌入式
【发布时间】:2012-10-16 04:03:34
【问题描述】:

我使用 Mongoose.js,无法解决 3 级层次文档的问题。

有两种方法。

第一 - 没有参考。

C = new Schema({
    'title': String,
});

B = new Schema({
    'title': String,
    'c': [C]
});

A = new Schema({
    'title': String,
    'b': [B]
});

我需要显示 C 记录。我如何填充/找到它,只知道 C 的 _id?

我正在尝试使用:

A.findOne({'b.c._id': req.params.c_id}, function(err, a){
    console.log(a);
});

但我不知道如何从 returnet 中获取我需要的仅 c 对象。

其次如果使用 refs:

C = new Schema({
    'title': String,
});

B = new Schema({
    'title': String,
    'c': [{ type: Schema.Types.ObjectId, ref: 'C' }]
});

A = new Schema({
    'title': String,
    'b': [{ type: Schema.Types.ObjectId, ref: 'B' }]
});

如何填充所有 B、C 记录以获得层次结构?

我试图使用这样的东西:

A
.find({})
.populate('b')
.populate('b.c')
.exec(function(err, a){
    a.forEach(function(single_a){
        console.log('- ' + single_a.title);
        single_a.b.forEach(function(single_b){
            console.log('-- ' + single_b.title);
            single_b.c.forEach(function(single_c){
                console.log('--- ' + single_c.title);
            });
        });
    });
});

但它会为 single_c.title 返回 undefined。我有办法填充它吗?

谢谢。

【问题讨论】:

  • 既然支持,最好选择一个新的接受的答案。

标签: javascript node.js mongodb mongoose nosql


【解决方案1】:

在 Mongoose 4 中,您可以跨多个级别填充文档:

假设您有一个 User 架构来跟踪用户的朋友。

var userSchema = new Schema({
  name: String,
  friends: [{ type: ObjectId, ref: 'User' }]
});

首先populate() 让您获得用户好友列表。但是,如果您还想要用户的朋友的朋友怎么办?在这种情况下,您可以指定 populate 选项来告诉 mongoose 填充用户所有朋友的 friends 数组:

User.
  findOne({ name: 'Val' }).
  populate({
    path: 'friends',
    // Get friends of friends - populate the 'friends' array for every friend
    populate: { path: 'friends' }
  });

取自:http://mongoosejs.com/docs/populate.html#deep-populate

【讨论】:

【解决方案2】:

从 Mongoose 3.6 开始,在查询中添加了 the ability to recursively populate related documents。以下是您可能如何做到的示例:

 UserList.findById(listId)
         .populate('refUserListItems')
         .exec(function(err, doc){
             UserListItem.populate(doc.refUserListItems, {path:'refSuggestion'},
                   function(err, data){
                        console.log("User List data: %j", doc);
                        cb(null, doc);
                   }
             );     
          });           

在这种情况下,我在 'refUserListItems' 中使用他们引用的文档填充一个 id 数组。然后,查询的结果会被传递到另一个填充查询,该查询引用我想要填充的原始填充文档的字段 - 'refSuggestion'。

注意第二个(内部)填充 - 这就是魔法发生的地方。您可以继续嵌套这些填充并添加越来越多的文档,直到按照您需要的方式构建图表。

这需要一点时间来消化它是如何工作的,但如果你完成它,它是有意义的。

【讨论】:

  • 这行得通,但是上面 Buu Nguyen 给出的深度填充更方便。不需要做嵌套循环..
  • 如何使用 Promise 做到这一点?
  • @steampowered - 哪一部分?您可以将整个事情包装在一个返回承诺的函数中,并将回调中的承诺解析为 .populate。看起来 .populate 也返回了一个 Promise,因此您可以在任何一个 .populate 函数上捕获此 Promise,然后在您想要运行它时调用 .then 。
  • @BoxerBucks 我决定返回 .populate().then() 函数链中返回的承诺,最后用最后一个 .then() 运行它。我认为这看起来比嵌套 n 级人口更干净。 stackoverflow.com/a/32018947/404699
  • 如果我必须找到文档而不是单个文档怎么办,我应该遍历它们中的每一个以填充内部路径还是有办法在所有这些上完成它
【解决方案3】:

我来晚了,但我写了一个Mongoose plugin,它使得执行深度模型填充变得非常简单。对于您的示例,您可以执行此操作来填充 bc

A.find({}, function (err, docs) {
  A.deepPopulate(docs, 'b.c', cb)
}

您还可以为每个填充路径指定Mongoose populate options,如下所示:

A.deepPopulate(docs, 'b.c', {
  b: { 
    select: 'name'
  }
}, cb)

查看插件documentation 了解更多信息。

【讨论】:

  • 这看起来很酷。当它变得更成熟时,我可能会在生产中使用它。
  • b: ment 不是 c: 吗?
【解决方案4】:

在 Mongoose 4 中,您可以像这样填充多级(即使在不同的数据库或实例中)

A
.find({})
.populate({
  path: 'b', 
  model: 'B',
  populate: {
    path: 'c',
    model: 'C'
  }
})
.exec(function(err, a){});

【讨论】:

  • 这绝对应该标记为正确答案+1
  • 一个小偏差.. 如果B = new Schema({ 'title': String, 'c': [{ type: Schema.Types.ObjectId, ref: 'C' }], 'cc': [{ type: Schema.Types.ObjectId, ref: 'C' }] }); 我如何填充 c 和 cc 会发生什么?
  • 您可以像这样在链填充中执行 .populate('c').populate('cc') 。这就是你想要的吗?
  • 甚至 B.populate([{path: 'c'}, {path: 'cc'}])
猜你喜欢
  • 2015-02-09
  • 2015-07-13
  • 2016-10-10
  • 2014-07-28
  • 2019-09-16
  • 2021-07-26
  • 2015-09-21
相关资源
最近更新 更多