Mongoose – Come raggruppare e popolare?

Io uso MongoDB e Mongoose come mio ODM e sto cercando di fare una query usando populate e group by nella stessa istruzione.

Ecco i miei modelli di documenti semplici:

 var userSchema = new Schema({ username: String }); var messageSchema = new Schema({ from: { type: Schema.ObjectId, ref: 'User' }, to: { type: Schema.ObjectId, ref: 'User' }, message: String, date: { type: Date, default: Date.now } }); 

Sto solo cercando di ottenere tutti i messaggi per un utente, gruppo per ogni utente con cui parla. Ho provato così:

 this.find({ 'to': user }) .sort({ 'date': 1 }) .group('from') .populate(['from', 'to']) .exec(callback); 

Ma, sfortunatamente, il mio modello non ha un metodo di group . Hai qualche soluzione per farlo funzionare?

Grazie.

Esempio utilizzando $ pop-up di ricerca, la ricerca popola come una matrice, da cui il $ unwind.

 Message.aggregate( [ { "$match": { "to": user } }, { "$sort": { "date": 1 } }, { "$group": { "_id": "from", "to": { "$first": "$to" }, "message": { "$first": "$message" }, "date": { "$first": "$date" }, "origId": { "$first": "$_id" } }}, { "$lookup": { "from": "users", "localField": "from", "foreignField": "_id", "as": "from" }}, { "$lookup": { "from": "users", "localField": "to", "foreignField": "_id", "as": "to" }}, { "$unwind": { "path" : "$from" } }, { "$unwind": { "path" : "$to" } } ], function(err,results) { if (err) throw err; return results; } ) 

L’opzione migliore da usare qui è .aggregate() , che è un’implementazione del codice nativo a differenza del metodo .group() di MongoDB che utilizza il motore JavaScript per elaborare i risultati.

Metodi come .populate() non sono tuttavia direttamente supportati, e questo è in base alla progettazione poiché la pipeline di aggregazione e altri metodi non restituiscono rigorosamente una risposta basata sullo schema del modello corrente. Dal momento che sarebbe sbagliato “assumere” questo è ciò che stai facendo, è solo una risposta dell’object grezzo.

Tuttavia, non vi è nulla che ti impedisca di “trasmettere” la risposta come documenti di mangusta e quindi chiamare il modulo del modello di .populate() con i percorsi richiesti:

 Message.aggregate( [ { "$match": { "to": user } }, { "$sort": { "date": 1 } }, { "$group": { "_id": "from", "to": { "$first": "$to" }, "message": { "$first": "$message" }, "date": { "$first": "$date" }, "origId": { "$first": "$_id" } }} ], function(err,results) { if (err) throw err; results = result.map(function(doc) { doc.from = doc._id doc._id = doc.origId; delete doc.origId; return new Message( doc ) }); User.populate( results, { "path": "from to" }, function(err,results) { if (err) throw err; console.log( JSON.stringify( results, undefined, 4 ) ); }); } ) 

Ovviamente, questo restituisce davvero il $first di ciascun “da” come è implicito dall’operatore.

Forse ciò che intendi per “raggruppare per” è in realtà “ordinare”:

 Message.find({ "to": user }) .sort({ "from": 1, "date": 1 }) .populate("from to") .exec(function(err,messsages) { if (err) throw err; console.log( JSON.stringify( messages, undefined, 4 ) ); }); 

Come il tuo contesto dice “tutti i messaggi” e non qualcosa che sarebbe altrimenti implicito da un operatore di raggruppamento come con .aggregate() o il metodo di raccolta .group() . Quindi i messaggi sono “raggruppati” tramite l’ordinamento, piuttosto che un particolare raggruppamento.

Quest’ultimo suona come quello che stai veramente chiedendo, ma se in realtà intendevi un vero “raggruppamento”, allora c’è l’esempio di aggregazione insieme a come usare .populate() con quello.