2012-10-25 10 views
24

Io uso Mongoose.js e non posso risolvere il problema con il documento di gerarchia a 3 livelli.Popolo popolato incorporato

Ci sono 2 modi per farlo.

Primo - senza ref.

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

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

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

Ho bisogno di mostrare C record. Come posso popolare/trovarlo, conoscendo solo _id di C?

ero uso prova:

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

ma non so come andare da Returnet un oggetto unico oggetto C che ho bisogno.

Seconda se si lavora con arbitri:

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

come popolare tutti i B, record C per ottenere la gerarchia?

ero tenta di utilizzare qualcosa di simile:

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

Ma tornerà definito per single_c.title. C'è modo di popolarlo?

Grazie.

+1

Sarebbe bene scegliere una nuova risposta accettato ora che questo è supportato. – JohnnyHK

risposta

24

in Mongoose 4 è possibile popolare i documenti su più livelli:

Diciamo che avete un utente schema che tiene traccia di amici dell'utente.

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

populate() consente di ottenere un elenco di amici di un utente. Ma cosa succede se si desidera anche amici di amici di un utente? Specificare l'opzione populate per dire mangusta per popolare la matrice friends di tutti gli amici dell'utente:

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

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

+0

La stessa risposta di aaron da una domanda simile http://stackoverflow.com/q/11137239/728287 –

+2

FYI - questo è stato risolto nella versione 3.6 - https://github.com/LearnBoost/mongoose/wiki/3.6-Release -Note – BoxerBucks

+0

@BoxerBucks potresti fornire un esempio? (il caso con refs) – fusio

41

Come di Mongoose 3,6 the ability to recursively populate related documents in una query è stato aggiunto. Ecco un esempio di come si potrebbe farlo:

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

In questo caso, sto popolando un array di id in 'refUserListItems' con i loro documenti di riferimento. Il risultato della query viene quindi passato in un'altra query popolata che fa riferimento al campo del documento originale popolato che desidero anche compilare: 'refSuggestion'.

Nota il secondo (interno) popola - questo è dove avviene la magia. Puoi continuare a nidificare questi popolamenti e virare su un numero sempre maggiore di documenti finché non hai costruito il tuo grafico nel modo in cui ne hai bisogno.

Ci vuole un po 'di tempo per capire come funziona, ma se ci riesci, ha senso.

+0

sicuramente! grazie :) – fusio

+0

questo funziona, ma il popolamento profondo dato da Buu Nguyen sopra, è più conveniente. Non è necessario fare cicli nidificati .. –

+0

Come posso fare questo usando le promesse? – steampowered

4

Sono in ritardo, ma ho scritto uno Mongoose plugin che rende estremamente semplice l'esecuzione di una popolazione di modelli profondi. Per il vostro esempio, si può fare questo per popolare b e c:

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

è anche possibile specificare Mongoose populate options per ciascuno dei percorsi popolate, come questo:

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

Partenza il plugin documentation per più informazione.

+0

Questo sembra davvero fantastico. Potrei usarlo in produzione quando diventerà più maturo. – steampowered

+0

Non è il b: ment essere un c:? –

27

in Mongoose 4 è possibile popolare multilivello come questo (anche in diverso database o l'istanza)

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

Questo dovrebbe essere sicuramente contrassegnato come la risposta corretta +1 –

+0

Questo è disponibile solo nella versione più recente, quindi ... –

+3

Questa dovrebbe essere la risposta giusta. +1 – CENT1PEDE

Problemi correlati