Порядок ответов на запрос 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] } );
}
Ответ 5
$или обходной путь больше не работает в 2.6.x, см. https://jira.mongodb.org/browse/SERVER-14083. Здесь реализована реализация Ruby: https://gist.github.com/dblock/d5ed835f0147467a6a27
Ответ 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);
});