2012-10-25 12 views
24

Używam Mongoose.js i nie mogę rozwiązać problemu z dokumentem 3 poziomu hierarchii.Mongoose populate embedded

Są 2 sposoby na zrobienie tego.

Pierwsza - bez informacji.

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

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

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

Potrzebuję pokazać C rekord. Jak mogę go wypełnić/znaleźć, znając tylko _id z C?

byłem stosowanie try:

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

ale nie wiem jak dostać się z returnet obiekt tylko c object, że muszę.

drugie jeśli pracuje z literatury:

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

Jak wypełnić wszystkie B, C, aby uzyskać rekordy hierarchii?

miałem spróbować użyć czegoś takiego:

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

Ale powróci niezdefiniowana dla single_c.title. Czy mogę go zaludnić?

Dzięki.

+1

Byłoby dobrze, aby wybrać nową odpowiedź akceptowanej teraz, że to jest obsługiwane. – JohnnyHK

Odpowiedz

24

w Mongoose 4 można wypełnić dokumenty na wielu poziomach:

Say masz użytkownika schemat, który śledzi znajomych użytkownika.

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

populate() pozwala uzyskać listę znajomych użytkownika. Ale co, jeśli chciałbyś również przyjaciół znajomych? Określić opcję populate powiedzieć mangusty, aby wypełnić tablicę friends wszystkich znajomych użytkownika:

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

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

+0

Ta sama odpowiedź od Aarona z podobnego pytania http://stackoverflow.com/q/11137239/728287 –

+2

FYI - zostało to rozwiązane w wersji 3.6 - https://github.com/LearnBoost/mongoose/wiki/3.6-Release -Notes – BoxerBucks

+0

@BoxerBucks mógłby podać przykład? (sprawa z dopisek) – fusio

41

Od Mongoose 3,6 the ability to recursively populate related documents w zapytaniu został dodany. Oto przykład, jak można to zrobić:

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

W tym przypadku jestem wypełniania tablicę identyfikatorów w „refUserListItems” z ich odnośnych dokumentów. Wynik zapytania zostaje następnie przekazany do innego zapytania, które odwołuje się do pola pierwotnie wypełnionego dokumentu, który chcę również wypełnić - "refSuggestion".

Uwaga na drugi (wewnętrzny) obszar - w tym miejscu dzieje się magia. Możesz dalej zagnieżdżać te populacje i dostosowywać je do coraz większej liczby dokumentów, dopóki nie zbudujesz wykresu tak, jak tego potrzebujesz.

Potrwa to trochę czasu, aby przetłumaczyć, jak to działa, ale jeśli przejdziesz przez to, ma to sens.

+0

zdecydowanie! dzięki :) – fusio

+0

to działa, ale głębokie zaludnienie podane przez Buu Nguyena powyżej, jest wygodniejsze. Nie trzeba wykonywać zagnieżdżonych pętli. –

+0

Jak mogę to zrobić, korzystając z obietnic? – steampowered

4

Spóźniłem się na to, ale napisałem Mongoose plugin, który sprawia, że ​​niezwykle proste jest wykonywanie głębokiej populacji modeli. Na swoim przykładzie, można to zrobić, aby zapełnić b i c:

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

Można również określić Mongoose populate options dla każdego z zaludnionych ścieżek, tak:

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

Sprawdź wtyczki documentation dłużej Informacja.

+0

To wygląda naprawdę fajnie. Mogę go użyć w produkcji, gdy stanie się bardziej dojrzały. – steampowered

+0

Czy b: ment nie jest c:? –

27

w Mongoose 4 można wypełnić wielopoziomowe jak to (nawet w innej bazy danych lub instancji)

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

To powinno być zdecydowanie oznaczone jako poprawna odpowiedź +1 –

+0

Jest to dostępne tylko w nowszej wersji, więc ... –

+3

To powinna być właściwa odpowiedź. +1 – CENT1PEDE