MongoDB
MongoDB: как оставить в массиве элемент с максимальным значением
Если в документе MongoDB есть массив объектов и нужно оставить только элемент с максимальным значением, удобный путь — использовать update с aggregation pipeline: отсортировать массив по нужному полю и взять первый элемент. Например, если в массиве scores лежат результаты игроков, можно оставить только объект с максимальным points
Пример документа:
db.players.insertOne({
name: "Team A",
scores: [
{ player: "Anna", points: 12 },
{ player: "Boris", points: 27 },
{ player: "Mira", points: 19 }
]
})
Нужно получить:
{
name: "Team A",
scores: [
{ player: "Boris", points: 27 }
]
}
Решение через $sortArray и $slice
db.players.updateMany(
{},
[
{
$set: {
scores: {
$slice: [
{
$sortArray: {
input: "$scores",
sortBy: { points: -1 }
}
},
1
]
}
}
}
]
)
Что здесь происходит:
$sortArrayсортирует массивscoresпоpointsпо убыванию;$sliceберет первый элемент отсортированного массива;$setзаписывает результат обратно в полеscores.
Проверка
db.players.findOne({ name: "Team A" })
В массиве scores должен остаться один объект с максимальным points
Если нужно не менять документ, а только вывести максимум
Иногда лучше не обновлять базу, а просто получить лучший элемент в результате запроса:
db.players.aggregate([
{
$project: {
name: 1,
bestScore: {
$slice: [
{
$sortArray: {
input: "$scores",
sortBy: { points: -1 }
}
},
1
]
}
}
}
])
Так исходный массив в документе останется прежним
Что делать при одинаковом максимальном значении
Если несколько элементов имеют одинаковый максимум, $slice: 1 оставит только первый после сортировки. Если нужно оставить все элементы с максимальным значением, лучше сначала посчитать максимум, а потом отфильтровать массив. Это уже отдельный сценарий
Для большинства задач вроде «оставить лучший результат» достаточно одного элемента
Частые ошибки
Сортируют по строке вместо числа
Если points хранится как строка, сортировка будет работать не так, как вы ожидаете. Храните числа числами:
points: 27
а не так:
points: "27"
Перезаписывают весь документ
Используйте $set, чтобы изменить только поле scores, а не заменить документ целиком
Меняют данные, хотя нужен только отчет
Если вам нужно просто показать максимум в интерфейсе, используйте aggregate() с $project. Обновление документа нужно только тогда, когда вы действительно хотите удалить остальные элементы массива
Не проверяют пустой массив
Если у части документов scores пустой, результат тоже будет пустым массивом. Это нормально, но лучше заранее понимать, есть ли такие документы
Что почитать дальше по MongoDB
Если нужен общий маршрут по теме, откройте рубрику MongoDB. Для соседних задач пригодятся эти разборы:
- Как переместить элемент в массиве MongoDB
- Как обновить ключ у всех объектов в массиве MongoDB
- Discord bot на Python и MongoDB: как задать проверку
- Failed to start MongoDB database server: что проверить
Как проверить результат на практике
Для MongoDB-материала полезно делать три проверки: сначала выполнить команду на маленьком наборе тестовых документов, затем посмотреть результат через find() или MongoDB Compass, а после этого повторить действие на копии реальной структуры данных. Если запрос меняет документы, сначала запускайте его с фильтром на один документ и только потом расширяйте условие
Еще одна хорошая привычка — записывать исходное состояние и ожидаемый результат. Например: было три документа, после обновления изменился только один; был массив из пяти элементов, после операции остался нужный элемент; индекс появился в getIndexes(). Такая проверка быстро показывает, что вы исправили именно задачу, а не просто получили команду без ошибки