Order of responses to MongoDB $in query?

Mongodb

Mongodb Problem Overview


The MongoDB docs on the $in conditional operator don't say anything about order. If I run a query of the form

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

what will be the order of the returned results? And is there a way for me to tell MongoDB "I want the results sorted so that they're in the same order as the ids in id_array?"

Mongodb Solutions


Solution 1 - Mongodb

Asked for this feature on JIRA:

Quickly got a pretty good response: use $or instead of $in

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

vs.

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

Read the bug report for more info.

Update:

The $or work-around hack no longer works starting with 2.6.x - it was a side effect of implementation which has changed.

Solution 2 - Mongodb

I had the same problem and my solution was to create a hash map to do the mapping between my array of ids (my query) and my array of results from MongoDB.

The extra work is to browse the array of results and to insert, for each item, a new key-value pair: the key is the ID and the value is the result object.

Then, when I want to browse my results in the same order as my query was, I can use the hashmap to retrieve the correct object. No sorting, and no fancy Mongo DB option.

In Javascript it would be something like:

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

This will display:

a
b
c
d

Solution 3 - Mongodb

@Jason 's answer is the correct one.

About other answers: I wouldn't recommend querying one by one because it can bring serious performance issues.

In addition to @Jason 's answer, it can be optimised using Array.reduce and Array.map methods, like this:

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

Solution 4 - Mongodb

the order of the results isn't mentioned because they won't be ordered in any dependable way. the only way to get them ordered would be to do separate queries client-side for each item in the $in array

Solution 5 - Mongodb

If you don't mind using Underscore.js and aren't too worried about scale (IE, you don't mind fetch-ing rather than working with the cursor) , here's how I maintained order:

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

Solution 6 - Mongodb

The $or workaround no longer works in 2.6.x, see https://jira.mongodb.org/browse/SERVER-14083. Here's a Ruby workaround implementation: https://gist.github.com/dblock/d5ed835f0147467a6a27

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTrevor BurnhamView Question on Stackoverflow
Solution 1 - MongodbJonathan OngView Answer on Stackoverflow
Solution 2 - MongodbJasonView Answer on Stackoverflow
Solution 3 - MongodbDavid Rissato CruzView Answer on Stackoverflow
Solution 4 - MongodbmdirolfView Answer on Stackoverflow
Solution 5 - MongodbAlexeyView Answer on Stackoverflow
Solution 6 - MongodbdB.View Answer on Stackoverflow