Ordine delle risposte a MongoDB $ in query?

I documenti MongoDB sull’operatore $ in condizionale non dicono nulla sull’ordine. Se eseguo una query del modulo

db.things.find({'_id': {'$in': id_array}}); 

quale sarà l’ordine dei risultati restituiti? E c’è un modo per me di dire a MongoDB “Voglio che i risultati siano ordinati in modo che siano nello stesso ordine degli id ​​di id_array ?”

Chiesto questa funzione su JIRA :

Ottenuto rapidamente una buona risposta: usa $or invece di $in

 c.find( { _id:{ $in:[ 1, 2, 0 ] } } ).toArray() 

vs.

 c.find( { $or:[ { _id:1 }, { _id:2 }, { _id:0 } ] } ).toArray() 

Leggi la segnalazione di bug per maggiori informazioni.

Aggiornamento :

La modifica $ o work-around non funziona più a partire da 2.6.x – è stato un effetto collaterale dell’implementazione che è cambiato .

Ho avuto lo stesso problema e la mia soluzione era creare una mappa hash per fare il mapping tra la mia matrice di id (la mia query) e il mio array di risultati da MongoDB.

Il lavoro extra è quello di sfogliare l’array di risultati e inserire, per ogni articolo, una nuova coppia chiave-valore: la chiave è l’ID e il valore è l’object risultato.

Quindi, quando voglio sfogliare i miei risultati nello stesso ordine della mia query, posso usare l’hashmap per recuperare l’object corretto. Nessun ordinamento e nessuna opzione di Mongo DB.

In Javascript sarebbe qualcosa di simile:

 //The order you want var queryIds = [ 8, 5, 3, 7 ]; //The results from MongoDB in an undefined order var resultsFromMongoDB = [ {_id: 7, data: "d" }, {_id: 8, data: "a" }, {_id: 5, data: "b" }, {_id: 3, data: "c" }, ]; //The function to create a hashmap to do the mapping function createHashOfResults( results ){ var hash = {}; for( var i = 0 ; i < results.length ; i++ ){ var item = results[i]; var id = item._id; hash[ id ] = item; } return hash; } //Let's build the hashmap var hash = createHashOfResults( resultsFromMongoDB ); //Now we can display the results in the order we want for( var i = 0 ; i < queryIds.length ; i++ ){ var queryId = queryIds[i]; var result = hash[queryId]; console.log( result.data ); } 

Questo mostrerà:

 a b c d 

La risposta di @Jason è corretta.

Informazioni su altre risposte: non consiglierei di eseguire una query una alla volta perché può causare seri problemi di prestazioni.

Oltre alla risposta di @Jason, può essere ottimizzata usando i metodi Array.reduce e Array.map, come questo:

 //The order you want var queryIds = [8, 5, 3, 7]; //The results from MongoDB in an undefined order var resultsFromMongoDB = [ {_id: 7, data: "d"}, {_id: 8, data: "a"}, {_id: 5, data: "b"}, {_id: 3, data: "c"} ]; var reorderedResults = naturalOrderResults(resultsFromMongoDB, queryIds); function naturalOrderResults(resultsFromMongoDB, queryIds) { //Let's build the hashmap var hashOfResults = resultsFromMongoDB.reduce(function (prev, curr) { prev[curr._id] = curr; return prev; }, {}); return queryIds.map( function(id) { return hashOfResults[id] } ); } 

l’ordine dei risultati non è menzionato perché non saranno ordinati in modo affidabile. l’unico modo per ottenerli ordinati consiste nel fare query separate lato client per ogni elemento nell’array $ in

$ O soluzione alternativa non funziona più in 2.6.x, vedere https://jira.mongodb.org/browse/SERVER-14083 . Ecco una soluzione alternativa per Ruby: https://gist.github.com/dblock/d5ed835f0147467a6a27

Se non ti dispiace usare Underscore.js e non sei troppo preoccupato per la scalabilità (IE, non ti dispiace fetch -ing piuttosto che lavorare con il cursore), ecco come ho mantenuto l’ordine:

 var results = db.things.find({'_id': {'$in': id_array}}).fetch(); return _.sortBy(results, function(thing) { return id_array.indexOf(thing._id); });