Страницы

Поиск по вопросам

вторник, 10 декабря 2019 г.

Как оставить в массиве элемент с максимальным значением

#mongodb #aggregation_framework #mongodb_query


У меня следующие документы в коллекции

{
   "_id": 1,
   "values":[
      {
         "value1":10,
         "value2":12,
         "value3":30
      },
      {
         "value1":20,
         "value2":12,
         "value3":100
      },
      {
         "value1":30,
         "value2":14,
         "value3":50
      }
   ]
},
{
   "_id": 2,
   "values":[
      {
         "value1":10,
         "value2":12,
         "value3":60
      },
      {
         "value1":20,
         "value2":12,
         "value3":80
      },
      {
         "value1":30,
         "value2":14,
         "value3":70
      }
   ]
}


Мне нужно оставить один документ с одним элементом в массиве по следующим критериям:

values.value1 = 20
values.value2 = 12
values.value3  // максимальное значение из всех значений values.value3 во всех документах


Например, по вышеуказанным критериям должен получиться такой документ:

{
   "_id": 1,
   "values":[
      {
         "value1":20,
         "value2":12,
         "value3":100
      }
   ]
}


Также, подойдет решение, просто сортирующие документы и элементы по указанным критериям.
Чтобы первым документом был тот, в котором значение values.value3 максимально из возможных
и первым элементом в массиве был объект с максимальным значением. Например:

{
   "_id": 1,
   "values":[
     {
         "value1":20,
         "value2":12,
         "value3":100
      },
      {
         elements...
      }
   ]
},
{
   "_id": 2,
   "values":[
      {
         elements...
      }
   ]
}


Сделать это у меня получается, но я использую $match, $unwind, $group, $redact, $sort
по несколько раз. Может быть кто-то предложит более правильную реализацию.
    


Ответы

Ответ 1



Лучший способ это запустить два запроса. Первый, чтобы нашел максимальное значение и второй, чтобы остался только документ, где value3 равно этому значению. Решение для MongoDB версия 3.2 или новее: Начиная с версии 3.2 можно использовать оператор $max, который возвращает максимальное значение для каждого документа в $project этапе. Оператор $map здесь возвращает массив value3. Следующий этап в цепочке — это $group, где нужно группировать документы и возвращать максимальное значение. var result = db.collection.aggregate([ { "$project": { "maxVal": { "$max": { "$map": { "input": "$values", "as": "value", "in": "$$value.value3" } } } } }, { "$group": { "_id": null, "mval": { "$max": "$maxVal" } } } ]); Поскольку метод .aggregate() возвращает курсор, нужно использовать метод toArray() и оператор [] для получения значения. var maximumValue = result.toArray()[0]['mval']; Теперь можно использовать это значение, чтобы оставить в массиве только элемент с максимальным значением. Для этого нужно использовать оператор $filter db.collection.aggregate( [ { "$match": { "values.value3": maximumValue } }, { "$project": { "values": { "$filter": { "input": "$values", "as": "value", "cond": { "$eq": [ "$$value.value3", maximumValue ] } } } } } ]) Решение для MongoDB версии 2.6 или новее: Решение для версий с 2.6 по 3.2 менее эффективно. Сначала в первом запросе нужно денормализовать массив value3 сразу после $project, используя оператор $unwind. Последний этап в цепочке это $group, где группируем документы и возвращаем максимальное значение value3 var result = db.collection.aggregate([ { "$project": { "value3": { "$map": { "input": "$values", "as": "value", "in": "$$value.value3" } } } }, { "$unwind": "$value3" }, { "$group": { "_id": null, "mval": { "$max": "$value3" } } } ]); var maximumValue = result.toArray()[0]['mval']; Чтобы оставить в массиве только элемент с максимальным значением, у нас есть два варианта: Используя оператор $redact db.collection.aggregate( [ { "$match": { "values.value3": maximumValue } }, { "$redact": { "$cond": [ { "$or": [ { "$eq": [ "$value3", maximumValue ] }, { "$not": "$value3" } ]}, "$$DESCEND", "$$PRUNE" ] }} ]) Используя оператор $project и $setDifference db.collection.aggregate( [ { "$match": { "values.value3": maximumValue } }, { "$project": { "values": { "$setDifference": [ { "$map": { "input": "$values", "as": "value", "in": { "$cond": [ { "$eq": [ "$$value.value3", maximumValue ] }, "$$value", false ] } }}, [false] ] } }} ])

Комментариев нет:

Отправить комментарий