2012-10-25 194 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