Порядок ответов на запрос MongoDB $?

Документы MongoDB в $in условный оператор ничего не говорят о порядке. Если я запустил запрос формы

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

каков будет порядок возвращаемых результатов? И есть ли способ сказать MongoDB "Я хочу, чтобы результаты отсортировались так, чтобы они находились в том же порядке, что и идентификаторы в id_array?"

Ответ 1

Задана эта функция на JIRA:

Быстро получил неплохой ответ: используйте $or вместо $in

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

против.

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

Прочтите отчет об ошибке для получения дополнительной информации.

Обновление

Сбой $или work-around теперь больше не работает с 2.6.x - это был побочный эффект реализации, который изменился.

Ответ 2

У меня была та же проблема, и моим решением было создать хэш-карту, чтобы сделать сопоставление между моим массивом идентификаторов (мой запрос) и моим массивом результатов от MongoDB.

Дополнительная работа - просмотр массива результатов и вставка для каждого элемента новой пары ключ-значение: ключ - это идентификатор, а значение - результат.

Затем, когда я хочу просмотреть результаты в том же порядке, что и мой запрос, я могу использовать hashmap для извлечения правильного объекта. Нет сортировки, и нет модной опции Mongo DB.

В Javascript это будет что-то вроде:

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

Это отобразит:

a
b
c
d

Ответ 3

порядок результатов не упоминается, потому что они не будут упорядочены каким-либо надежным способом. единственный способ получить их заказ - это сделать отдельные запросы на стороне клиента для каждого элемента в массиве $in

Ответ 4

@Ответ Джейсона правильный.

О других ответах: я бы не стал рекомендовать один за другим, потому что это может привести к серьезным проблемам с производительностью.

В дополнение к ответу @Jason его можно оптимизировать с помощью методов Array.reduce и Array.map, например:

//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 build the hashmap
    var hashOfResults = resultsFromMongoDB.reduce(function (prev, curr) {
        prev[curr._id] = curr;
        return prev;
    }, {});

    return queryIds.map( function(id) { return hashOfResults[id] } );
}

Ответ 6

Если вы не возражаете против использования Underscore.js и не слишком беспокоитесь о масштабе (IE, вы не возражаете fetch -ing вместо работы с курсором), здесь, как я поддерживал порядок:

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