2012-10-25 189 views
24

我使用Mongoose.js并且无法解决3级别层次结构文档的问题。猫鼬填充嵌入式

有两种方法可以做到这一点。

First - without refs。

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对象,我需要。

如果与裁判工作:

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。我有办法填充它吗?

谢谢。

+1

将是一件好事,现在,这是支持选择一个新的接受的答案。 – JohnnyHK

回答

24

在猫鼬4您可以填写多个层面的文件:

假设你有一个用户架构以跟踪用户的朋友。

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

populate()让你得到一个用户的朋友列表。但是如果你还想要一个用户朋友的朋友呢?指定populate选项告诉猫鼬填充的所有用户的朋友的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

+0

同一个问题从类似的问题的回答 http://stackoverflow.com/q/11137239/728287 –

+2

仅供参考 - 这已在3.6版中解决 - https://github.com/LearnBoost/mongoose/wiki/3.6-发布-Notes – BoxerBucks

+0

@BoxerBucks你能提供一个例子吗? (案件与裁判) – fusio

41

查询中的猫鼬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); 
        } 
      );  
      });   

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

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

需要一点时间来消化这是如何工作的,但如果你通过它,它是有道理的。

+0

绝对!谢谢:) – fusio

+0

这个工作,但是由上面的Buu Nguyen给出的深度填充,更方便。没有必要做嵌套循环.. –

+0

我如何使用承诺来做到这一点? – steampowered

4

我迟到了,但我写了Mongoose plugin,这使得执行深度模型人口变得非常简单。更多

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

退房插件documentation:对于你的榜样,你可以做到这一点来填充bc

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

您还可以指定Mongoose populate options每个填充路径,这样信息。

+0

这看起来非常酷。当它变得更成熟时,我可能会在生产中使用它。 – steampowered

+0

b:不是c:? –

27

在猫鼬4您可以填充像这样多(甚至在不同的数据库或实例)

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

这绝对应该标记为正确答案+1 –

+0

这仅适用于新版本,因此... –

+3

这应该是正确答案。 +1 – CENT1PEDE