Mongodb - Найти документ с ближайшим целочисленным значением

Предположим, что у меня есть коллекция с документами с атрибутом отношения, который является числом с плавающей запятой.

{'ratio':1.437}

Как написать запрос, чтобы найти одиночный документ с ближайшим значением к заданному целому числу, не загружая их все в память с помощью драйвера и находя его с наименьшим значением abs(x-ratio)?

Ответ 1

Интересная проблема. Я не знаю, можете ли вы сделать это в одном запросе, но вы можете сделать это двумя:

var x = 1; // given integer
closestBelow = db.test.find({ratio: {$lte: x}}).sort({ratio: -1}).limit(1);
closestAbove = db.test.find({ratio: {$gt: x}}).sort({ratio: 1}).limit(1);

Затем вы просто проверяете, какой из двух документов имеет ratio, ближайший к целевому целю.

Обновление MongoDB 3.2

В выпуске 3.2 добавлена ​​поддержка оператора $abs абсолютного значения, который теперь позволяет сделать это в одном запросе aggregate

var x = 1;
db.test.aggregate([
    // Project a diff field that the absolute difference along with the original doc.
    {$project: {diff: {$abs: {$subtract: [x, '$ratio']}}, doc: '$$ROOT'}},
    // Order the docs by diff
    {$sort: {diff: 1}},
    // Take the first one
    {$limit: 1}
])

Ответ 2

У меня есть другая идея, но очень сложная задача и нужно изменить структуру данных.

Вы можете использовать индекс геолокации, который поддерживается mongodb

Сначала измените свои данные на эту структуру и сохраните второе значение с помощью 0

{'ratio':[1.437, 0]}

Затем вы можете использовать оператор $near, чтобы найти ближайшее значение отношения, и потому что оператор возвращает список, отсортированный по расстоянию, с заданным вами целым числом, вы должны использовать limit, чтобы получить только самое близкое значение.

db.places.find( { ratio : { $near : [50,0] } } ).limit(1)

Если вы не хотите этого делать, я думаю, вы можете просто использовать @JohnnyHK ответ:)