Как отсортировать результат после $setUnion в MongoDB

После применения $setUnion в MongoDB не стоит рассчитывать на исходный порядок элементов. $setUnion нужен, чтобы объединить массивы и убрать повторяющиеся значения. Если после этого нужен стабильный порядок, добавьте отдельную сортировку. В современных версиях MongoDB для массива удобно использовать $sortArray. В старых версиях можно развернуть массив через $unwind, отсортировать документы и собрать массив обратно

Пример документа:

{
  tagsA: ["css", "mongodb", "nodejs"],
  tagsB: ["python", "mongodb", "api"]
}

Объединение:

db.posts.aggregate([
  {
    $project: {
      tags: { $setUnion: ["$tagsA", "$tagsB"] }
    }
  }
])

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

Сортировка через $sortArray

Если ваша версия MongoDB поддерживает $sortArray, используйте такой pipeline:

db.posts.aggregate([
  {
    $project: {
      tags: {
        $sortArray: {
          input: { $setUnion: ["$tagsA", "$tagsB"] },
          sortBy: 1
        }
      }
    }
  }
])

sortBy: 1 сортирует по возрастанию, sortBy: -1 — по убыванию

Если массив состоит из объектов

Допустим, массив содержит объекты:

items: [
  { code: "b", title: "Beta" },
  { code: "a", title: "Alpha" }
]

Тогда сортировка по полю:

{
  $sortArray: {
    input: "$items",
    sortBy: { code: 1 }
  }
}

Так вы сортируете элементы массива по code

Вариант через $unwind

Если $sortArray недоступен, можно сделать так:

db.posts.aggregate([
  {
    $project: {
      tags: { $setUnion: ["$tagsA", "$tagsB"] }
    }
  },
  { $unwind: "$tags" },
  { $sort: { tags: 1 } },
  {
    $group: {
      _id: "$_id",
      tags: { $push: "$tags" }
    }
  }
])

Этот способ длиннее, но понятен: сначала объединяем, потом превращаем элементы массива в отдельные документы, сортируем и собираем обратно

Когда сортировать до $setUnion не поможет

Иногда пытаются отсортировать исходные массивы до объединения. Это не решает задачу надежно, потому что $setUnion заново формирует массив уникальных значений. Поэтому логика должна быть такой: сначала получить уникальное объединение, потом применить сортировку к уже готовому результату

Если результат нужен только для вывода на странице, сортировку можно сделать и в приложении. Но если дальше в pipeline есть стадии, которые зависят от порядка, лучше сортировать прямо в aggregation

Как проверить

Создайте тестовый документ с перемешанными значениями и выполните pipeline. Результат должен быть предсказуемым: например ["api", "css", "mongodb", "nodejs", "python"]

Частые ошибки

Ждут порядок от $setUnion

$setUnion решает задачу уникального объединения, а не сортировки. Сортировку добавляйте отдельно

Сортируют документы, а не массив

$sort сортирует документы pipeline. Для сортировки элементов массива используйте $sortArray или схему с $unwind

Забывают про версию MongoDB

Если $sortArray не работает, проверьте версию сервера и используйте вариант через $unwind

Сортируют строки как числа

Если в массиве лежат строки "10" и "2", строковая сортировка может дать неожиданный порядок. Для числовой сортировки храните числа числами

Что почитать дальше по MongoDB

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

Как проверить результат на практике

Для MongoDB-материала полезно делать три проверки: сначала выполнить команду на маленьком наборе тестовых документов, затем посмотреть результат через find() или MongoDB Compass, а после этого повторить действие на копии реальной структуры данных. Если запрос меняет документы, сначала запускайте его с фильтром на один документ и только потом расширяйте условие

Еще одна хорошая привычка — записывать исходное состояние и ожидаемый результат. Например: было три документа, после обновления изменился только один; был массив из пяти элементов, после операции остался нужный элемент; индекс появился в getIndexes(). Такая проверка быстро показывает, что вы исправили именно задачу, а не просто получили команду без ошибки

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x