Используя Spring Data Mongodb, возможно ли получить максимальное значение поля, не перетягивая и не перебирая всю коллекцию? - PullRequest
5 голосов
/ 30 марта 2012

Используя mongoTemplate.find(), я указываю Запрос, с помощью которого я могу вызвать .limit() или .sort():

.limit() возвращает Query объект
.sort() возвращает Sort object

Учитывая это, я могу сказать Query (). limit (int) .sort (), но это не выполняет желаемой операции, оно просто сортирует ограниченный набор результатов.

Я также не могу вызвать Query (). Sort (). Limit (int), поскольку .sort () возвращает Sort ()

Итак, используя Spring Data, как мне выполнить следующее, как показано в оболочке mongoDB?Может быть, есть способ передать необработанный запрос, который я еще не нашел?

Я бы согласился с расширением интерфейса пейджинга, если это необходимо ... просто, похоже, ничего не помогает.Спасибо!

> j = { order: 1 }
{ "order" : 1 }
> k = { order: 2 }
{ "order" : 2 }
> l = { order: 3 }
{ "order" : 3 }
> db.test.save(j)
> db.test.save(k)
> db.test.save(l)
> db.test.find()
{ "_id" : ObjectId("4f74d35b6f54e1f1c5850f19"), "order" : 1 }
{ "_id" : ObjectId("4f74d3606f54e1f1c5850f1a"), "order" : 2 }
{ "_id" : ObjectId("4f74d3666f54e1f1c5850f1b"), "order" : 3 }
> db.test.find().sort({ order : -1 }).limit(1)
{ "_id" : ObjectId("4f74d3666f54e1f1c5850f1b"), "order" : 3 }

Ответы [ 4 ]

3 голосов
/ 30 марта 2012

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

  • с Map / Reduce.Это эффективно просматривает все записи, но более оптимизировано (работает с несколькими потоками и в кластерах).Вот учебник map / lower для MongoDB.

  • предварительно вычислите максимальное значение для каждой вставки и сохраните его отдельно.Таким образом, всякий раз, когда вы вставляете запись, вы сравниваете ее с предыдущим максимальным значением, и, если оно больше - обновляете максимальное значение в БД.в коде.Это самое тривиальное решение.Это, вероятно, будет хорошо работать для небольших наборов данных.

Выбор одного из другого зависит от того, как вы используете это максимальное значение.Если это выполняется редко, например, для некоторых угловых отчетов, вы можете пойти с картой / уменьшить.Если он используется часто, то сохраните текущий максимум.

2 голосов
/ 11 октября 2016

Вы можете сделать это в sping-data-mongodb.Mongo оптимизирует комбинации сортировки и ограничения, если поле сортировки проиндексировано (или поле @Id).Это дает очень быстрый O (logN) или лучшие результаты.В противном случае это все равно O (N), а не O (N * logN), поскольку он будет использовать алгоритм top-k и избегать глобальной сортировки ( mongodb sort doc) .Это из примера Mkyong , но сначала я делаю сортировку и устанавливаю ограничение в одну секунду.

Query query = new Query();
query.with(new Sort(Sort.Direction.DESC, "idField"));
query.limit(1);
MyObject maxObject = mongoTemplate.findOne(query, MyObject.class);
1 голос
/ 30 марта 2012

Насколько мне известно, Mongo полностью поддерживает сортировку и ограничение: см. http://www.mongodb.org/display/DOCS/Sorting+and+Natural+Order

Получить максимум / мин через уменьшение карты будет очень медленно и его следует избегать любой ценой.

Я ничего не знаю о Spring Data, но могу порекомендовать Morphia для помощи с запросами. В противном случае базовый способ с драйвером Java будет:

DBCollection coll = db.getCollection("...");

DBCursor curr = coll.find(new BasicDBObject()).sort(new BasicDBObject("order", -1))
.limit(1);

if (cur.hasNext())
  System.out.println(cur.next());
0 голосов
/ 24 ноября 2015

Использовать агрегацию $ макс.Так как $ max является оператором-аккумулятором, доступным только на этапе $ group, вам нужно сделать хитрость.В операторе группы используйте любую константу как _id.
Давайте рассмотрим пример, приведенный на сайте Mongodb * только 1003 * -

Рассмотрим коллекцию sales со следующими документами:

{ "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-01-01T08:00:00Z") }
{ "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "date" : ISODate("2014-02-03T09:00:00Z") }
{ "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-03T09:05:00Z") }
{ "_id" : 4, "item" : "abc", "price" : 10, "quantity" : 10, "date" : ISODate("2014-02-15T08:00:00Z") }
{ "_id" : 5, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T09:05:00Z") }

Если вы хотите узнать максимальную цену среди всех предметов.

db.sales.aggregate(
   [
     {
       $group:
         {
           _id: "1", //** This is the trick
           maxPrice: { $max: "$price" }
         }
     }
   ]
)

Обратите внимание, что значение «_id» - это «1».Вы можете поставить любую константу ...

...