Страницы

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

Показаны сообщения с ярлыком mongodb-query. Показать все сообщения
Показаны сообщения с ярлыком mongodb-query. Показать все сообщения

пятница, 24 января 2020 г.

MongoDB - тормоз вставки после 5000000 записей

#java #база_данных #mongodb #nosql #mongodb_query


Всем привет. В общем проблема такая: Проект на JAVA и есть NoSQL DB - MongoDB, необходимо
работать примерно с 1000000000 записей. Вставка, в пустую таблицу, 5000000 записей,
происходит за 13-15 мин, но после вставки 5000000 дальнейший процесс вставки начинает
тормозить и чуть ли не в геометрической прогрессии и ОЗУ начинает пожирать немерено.
Приоритетной задачей этой БД является поиск (скорость поиска на 10000000 - удовлетворяющая)  

Вопрос: 


Почему так происходит?  
Как это исправить?


Возможные варианты решения:


Каждые 5000000 записей - создавать новую таблицу?
Оптимизация индексов? (у меня поиск по id)
Оптимизация конфига MongoDB?
Оптимизация системы?
Замена БД?


Заранее благодарен за ответ!
    


Ответы

Ответ 1



У меня был похожий случай когда я работал с SQLite. Приходилось перейти на MySQL. Но для миллиарда записей по моему вам надо будет перейти уже на BigTable. Например, на Hadoop, HBase или Cassandra. Насчет Cassandra если честно не уверен, потому что Facebook сам перешел от Cassandra на HBase хотя сами разработали ее. bigtableбаза-данных

среда, 18 декабря 2019 г.

Поиск документов, значение ключа у которых не выходит за рамки полученного массива

#mongodb #aggregation_framework #mongodb_query


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

animals = ['cat', 'dog', 'penguin']


то мне нужны документы где

animals = ['cat', 'dog', 'penguin']
animals = ['cat', 'dog']
animals = ['cat' 'penguin']
и т.д.


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


Ответы

Ответ 1



Если запрос достаточно сложный, и базовых средств либо знаний не хватает, то всегда можно воспользоваться механизмом $where. То есть можно написать сложную логику получения данных, включая if-ы, и вернуть результат, чего в обычных базах данных добиться очень и очень сложно (имею в виду условия и циклы внутри SQL-запросов). Синтаксис прост — в качестве параметра передаётся функция: db.foo.find({$where : функция}) При этом используется объект (переменная) this, по сути — курсор, у которой можно получать свойства. Функция должна вернуть true или false, что означает, попадёт строка в выборку или нет. Вот пример из википедии: db.foo.find({$where : function() { return this.x == this.y; }}) При этом также можно использовать вложенные OR или AND, как в классических SQL-запросах: db.foo.find({$where : function() { if((this.cost>5 && this.cost<10 )|| (this.is_hidden != 1) || (this.link == this.url)){ return true; } return false; }}) Таким образом, курсор пробегает по базе, и выполняет проверки. разумеется, всё это можно ограничивать лимитами на количество строк, $where — всего лишь ключ в массиве параметров запроса. Необходимо понимать, что это всё-таки медленне, чем обычные запросы, но всё равно достаточно быстро. скопировано отсюда по наводке из комментария автора вопроса.

Ответ 2



Я полагаю, у вас есть следующие документы в вашей коллекции. { "_id" : ObjectId("56ac7281ebc094e3677b809f"), "animals" : [ "rat", "cat" ] }, { "_id" : ObjectId("56ac7281ebc094e3677b80a0"), "animals" : [ "dog", "cat", "penguin" ] }, { "_id" : ObjectId("56ac7281ebc094e3677b80a1"), "animals" : [ "dog" ] }, { "_id" : ObjectId("56ac7281ebc094e3677b80a2"), "animals" : [ "cat", "dog" ] }, { "_id" : ObjectId("56ac7281ebc094e3677b80a3"), "animals" : [ "dog", "penguin" ] } и массив "animals": var animals = [ "cat", "dog", "penguin" ]; Лучший способ это делать это используя .aggregate() метод который обеспечивает доступ к агрегации цепочке. Первый этап в цепочке это $match где вы отфильтроваете документы, которые не имеют какой-либо элемента в массиве "animals". Это также уменьшает количество документов, которые будут обрабатываться в следующей стадии. Следующий и последний этап — это $redact. Здесь нужно использовать оператор $setIsSubset точно делает что мы хотим; он возврашает true если все элементы первого множество появляются во втором множество, в том числе, когда первый множеств равен второй; и также потому MongoDB не позволяет использовать $in в $cond. Конечно $$KEEP и $$PRUNE являются системные переменные. db.collection.aggregate([ { "$match": { "animals": { "$in": animals } } }, { "$redact": { "$cond": [ { "$setIsSubset": [ "$animals", animals ] }, "$$KEEP", "$$PRUNE" ] }} ]) Это запрос возврашает следующий результат: { "_id" : ObjectId("56ac7281ebc094e3677b80a0"), "animals" : [ "dog", "cat", "penguin" ] } { "_id" : ObjectId("56ac7281ebc094e3677b80a1"), "animals" : [ "dog" ] } { "_id" : ObjectId("56ac7281ebc094e3677b80a2"), "animals" : [ "cat", "dog" ] } { "_id" : ObjectId("56ac7281ebc094e3677b80a3"), "animals" : [ "dog", "penguin" ] } Здесь вам не нужно использовать оператор $where поскольку он вызовет падение производительности. $where evaluates JavaScript and cannot take advantage of indexes. Therefore, query performance improves when you express your query using the standard MongoDB operators (e.g., $gt, $in). In general, you should use $where only when you can’t express your query using another operator. If you must use $where, try to include at least one other standard query operator to filter the result set. Using $where alone requires a table scan. Конечно $redact не использует индексы. Он даже делает сканирования все документы в коллекции но более лучше.

суббота, 14 декабря 2019 г.

Как обновить несколько элементов в массиве?

#mongodb #aggregation_framework #mongodb_query


Необходимо обновить одним запросом несколько данных. Вот пример запроса:

db.coll.update(
  { article: 100500 },
  {
    $set: { a: 555 },
    $pull: { arr: { t: { $lt: 20 } } }
  }
);


А вот пример самого документа:

{
  article: 100500,
  a: 400,
  arr: [
    { t: 30, b: 12, n: 90 },
    { t: 10, b: 16, n: 60 }
  ]
}


Мой запрос:


Обновляет значение a на 555.
Удаляет все элементы массива arr, где t < 20.


Суть вопроса:
Надо обновить значения b в маccве arr. То есть, везде где n == 90, значение b надо
поменять на 777. Как можно дополнить этот запрос, чтобы "убить сразу 3-х зайцев"? 

В итоге должен получиться такой документ:

{
  article: 100500,
  a: 555, /* Тут было: 400 */
  arr: [
    { t: 30, b: 777, n: 90 },
    /* Тут был элемент массива */
  ]
}

    


Ответы

Ответ 1



Я полагаю, у вас есть следующие документы в вашей коллекции. { "_id" : ObjectId("56b71025973d202a52a5e650"), "article" : 100500, "a" : 400, "arr" : [ { "t" : 30, "b" : 12, "n" : 90 }, { "t" : 20, "b" : 16, "n" : 60 } ] }, { "_id" : ObjectId("56b7102b973d202a52a5e651"), "article" : 100500, "a" : 400, "arr" : [ { "t" : 0, "b" : 12, "n" : 90 }, { "t" : 10, "b" : 16, "n" : 60 } ] }, { "_id" : ObjectId("56b710d4973d202a52a5e652"), "article" : 100500, "a" : 400, "arr" : [ { "t" : 30, "b" : 12, "n" : 90 }, { "t" : 27, "b" : 16, "n" : 32 } ] } Прежде всего вы должны знать, что это не возможно, чтобы обновить более одного элемента в массиве используя метод update() даже с опцей multi: true или используя метод updateMany(); и все логики позади, что вы пытаетесь сделать; делать вещи более сложнее. Лучший способ это делать это используя Bulk Операции. Решение для MongoDB версия 3.2 или новее: MongoDB 3.2 не рекомендуется Bulk() и связанные с ним методы. Нужно использовать метод .bulkWrite() Здесь у нас есть два варианта: Нужно использовать агрегация чтотбы уменшать количество докуменьов которые нужно обновить. здесь в цепочке нужно только один этап: $project где мы используем оператор $filter. let requests = []; db.collection.aggregate([ { "$project": { "deleteElements": { "$filter": { "input": "$arr", "as": "del", "cond": { "$lt": [ "$$del.t", 12 ] } } }, "updateElements": { "$filter": { "input": "$arr", "as": "upd", "cond": { "$and": [ { "$gte": [ "$$upd.t", 12 ] }, { "$eq": [ "$$upd.n", 90 ] } ] } } } }} ]).forEach(function(document) { document.deleteElements.forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.t": element.t }, "update": { "$pull": { "arr": element } } } } ); }); document.updateElements.forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.t": element.n }, "update": { "$set": { "arr.$.b": 777 } } } } ); }); requests.push( { "updateOne": { "filter": { "_id": document._id }, "update": { "$set": { "a": 555 } } } } ); }) db.collection.bulkWrite(requests) Используя метод .find() db.collection.find({"article": 100500}).snapshot().forEach(function(document) { document.arr.filter(function(arr) { return arr.t < 12; }).forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.t": { "$lt": 12 }}, "update": { "$pull": { "arr": element } } } } ); }); document.arr.filter(function(arr) { return arr.n === 90; }).forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.n": 90 }, "update": { "$set": { "arr.$.b": 777 } } } } ); }); requests.push( { "updateOne": { "filter": { "_id": document._id }, "update": { "$set": { "a": 555 } } } } ); }) db.collection.bulkWrite(requests); Решение для MongoDB версии 2.6 или новее: var bulk = db.collection.initializeOrderedBulkOp(); var count = 0; db.collection.find({"article": 100500}).snapshot().forEach(function(document) { document.arr.filter(function(arr) { return arr.t < 12; }).forEach(function(element) { bulk.find({ "_id": document._id, "arr.t": { "$lt": 12 } } ).updateOne({ "$pull": { "arr": element } }); count++; }); document.arr.filter(function(arr) { return arr.n === 90; }).forEach(function(element) { bulk.find({ "_id": document._id, "arr.n": 90 }).updateOne({ "$set": { "arr.$.b": 777 } }); count++; }); bulk.find( { "_id": document._id } ).updateOne( { "$set": { "a": 555 } } ); count++; if (count % 1000 === 0) { // Выпольнить после 1000 операции bulk.execute(); bulk = db.collection.initializeOrderedBulkOp(); } }) // Очистить очереди if (count > 0) { bulk.execute(); } Результать { "_id" : ObjectId("56b71025973d202a52a5e650"), "article" : 100500, "a" : 555, "arr" : [ { "t" : 30, "b" : 777, "n" : 90 }, { "t" : 20, "b" : 16, "n" : 60 } ] } { "_id" : ObjectId("56b7102b973d202a52a5e651"), "article" : 100500, "a" : 555, "arr" : [ ] } { "_id" : ObjectId("56b710d4973d202a52a5e652"), "article" : 100500, "a" : 555, "arr" : [ { "t" : 30, "b" : 777, "n" : 90 }, { "t" : 27, "b" : 16, "n" : 32 } ] }

вторник, 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] ] } }} ])

вторник, 23 октября 2018 г.

Как обновить несколько элементов в массиве?

Необходимо обновить одним запросом несколько данных. Вот пример запроса:
db.coll.update( { article: 100500 }, { $set: { a: 555 }, $pull: { arr: { t: { $lt: 20 } } } } );
А вот пример самого документа:
{ article: 100500, a: 400, arr: [ { t: 30, b: 12, n: 90 }, { t: 10, b: 16, n: 60 } ] }
Мой запрос:
Обновляет значение a на 555 Удаляет все элементы массива arr, где t < 20
Суть вопроса: Надо обновить значения b в маccве arr. То есть, везде где n == 90, значение b надо поменять на 777. Как можно дополнить этот запрос, чтобы "убить сразу 3-х зайцев"?
В итоге должен получиться такой документ:
{ article: 100500, a: 555, /* Тут было: 400 */ arr: [ { t: 30, b: 777, n: 90 }, /* Тут был элемент массива */ ] }


Ответ

Я полагаю, у вас есть следующие документы в вашей коллекции.
{ "_id" : ObjectId("56b71025973d202a52a5e650"), "article" : 100500, "a" : 400, "arr" : [ { "t" : 30, "b" : 12, "n" : 90 }, { "t" : 20, "b" : 16, "n" : 60 } ] }, { "_id" : ObjectId("56b7102b973d202a52a5e651"), "article" : 100500, "a" : 400, "arr" : [ { "t" : 0, "b" : 12, "n" : 90 }, { "t" : 10, "b" : 16, "n" : 60 } ] }, { "_id" : ObjectId("56b710d4973d202a52a5e652"), "article" : 100500, "a" : 400, "arr" : [ { "t" : 30, "b" : 12, "n" : 90 }, { "t" : 27, "b" : 16, "n" : 32 } ] }

Прежде всего вы должны знать, что это не возможно, чтобы обновить более одного элемента в массиве используя метод update() даже с опцей multi: true или используя метод updateMany(); и все логики позади, что вы пытаетесь сделать; делать вещи более сложнее.
Лучший способ это делать это используя Bulk Операции
Решение для MongoDB версия 3.2 или новее:
MongoDB 3.2 не рекомендуется Bulk() и связанные с ним методы. Нужно использовать метод .bulkWrite()
Здесь у нас есть два варианта:
Нужно использовать агрегация чтотбы уменшать количество докуменьов которые нужно обновить. здесь в цепочке нужно только один этап: $project где мы используем оператор $filter
let requests = [];
db.collection.aggregate([ { "$project": { "deleteElements": { "$filter": { "input": "$arr", "as": "del", "cond": { "$lt": [ "$$del.t", 12 ] } } }, "updateElements": { "$filter": { "input": "$arr", "as": "upd", "cond": { "$and": [ { "$gte": [ "$$upd.t", 12 ] }, { "$eq": [ "$$upd.n", 90 ] } ] } } } }} ]).forEach(function(document) { document.deleteElements.forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.t": element.t }, "update": { "$pull": { "arr": element } } } } ); }); document.updateElements.forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.t": element.n }, "update": { "$set": { "arr.$.b": 777 } } } } ); }); requests.push( { "updateOne": { "filter": { "_id": document._id }, "update": { "$set": { "a": 555 } } } } ); })
db.collection.bulkWrite(requests) Используя метод .find()
db.collection.find({"article": 100500}).snapshot().forEach(function(document) { document.arr.filter(function(arr) { return arr.t < 12; }).forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.t": { "$lt": 12 }}, "update": { "$pull": { "arr": element } } } } ); }); document.arr.filter(function(arr) { return arr.n === 90; }).forEach(function(element) { requests.push( { "updateOne": { "filter": { "_id": document._id, "arr.n": 90 }, "update": { "$set": { "arr.$.b": 777 } } } } ); }); requests.push( { "updateOne": { "filter": { "_id": document._id }, "update": { "$set": { "a": 555 } } } } ); })
db.collection.bulkWrite(requests);

Решение для MongoDB версии 2.6 или новее:
var bulk = db.collection.initializeOrderedBulkOp(); var count = 0; db.collection.find({"article": 100500}).snapshot().forEach(function(document) { document.arr.filter(function(arr) { return arr.t < 12; }).forEach(function(element) { bulk.find({ "_id": document._id, "arr.t": { "$lt": 12 } } ).updateOne({ "$pull": { "arr": element } }); count++; }); document.arr.filter(function(arr) { return arr.n === 90; }).forEach(function(element) { bulk.find({ "_id": document._id, "arr.n": 90 }).updateOne({ "$set": { "arr.$.b": 777 } }); count++; }); bulk.find( { "_id": document._id } ).updateOne( { "$set": { "a": 555 } } ); count++; if (count % 1000 === 0) { // Выпольнить после 1000 операции bulk.execute(); bulk = db.collection.initializeOrderedBulkOp(); } })
// Очистить очереди if (count > 0) { bulk.execute(); }

Результать
{ "_id" : ObjectId("56b71025973d202a52a5e650"), "article" : 100500, "a" : 555, "arr" : [ { "t" : 30, "b" : 777, "n" : 90 }, { "t" : 20, "b" : 16, "n" : 60 } ] } { "_id" : ObjectId("56b7102b973d202a52a5e651"), "article" : 100500, "a" : 555, "arr" : [ ] } { "_id" : ObjectId("56b710d4973d202a52a5e652"), "article" : 100500, "a" : 555, "arr" : [ { "t" : 30, "b" : 777, "n" : 90 }, { "t" : 27, "b" : 16, "n" : 32 } ] }

вторник, 16 октября 2018 г.

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

У меня следующие документы в коллекции
{ "_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 по несколько раз. Может быть кто-то предложит более правильную реализацию.


Ответ

Лучший способ это запустить два запроса. Первый, чтобы нашел максимальное значение и второй, чтобы остался только документ, где 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] ] } }} ])