Как переместить элемент в массиве MongoDB

Чтобы переместить элемент в массиве MongoDB, надежнее всего прочитать документ, пересобрать массив в нужном порядке в приложении и записать новый массив через $set. В MongoDB есть операторы $pull, $push, $position, но универсальной команды «передвинь элемент с позиции 5 на позицию 2» для любого массива нет. Если порядок важен, лучше контролировать его явно

Допустим, документ задачи выглядит так:

{
  _id: ObjectId("665f1c1a7b8c2e0012a4d111"),
  title: "План урока",
  blocks: ["intro", "example", "practice", "faq"]
}

Нужно переместить practice сразу после intro

Вариант 1: пересобрать массив

В приложении логика выглядит так:

const doc = await db.collection("lessons").findOne({ _id: lessonId });

const item = "practice";
const withoutItem = doc.blocks.filter((block) => block !== item);
withoutItem.splice(1, 0, item);

await db.collection("lessons").updateOne(
  { _id: lessonId },
  { $set: { blocks: withoutItem } }
);

После этого массив станет таким:

["intro", "practice", "example", "faq"]

Этот способ понятен и хорошо работает, если массив не огромный и порядок меняет пользователь: например, перетаскивает пункты списка, блоки урока, фотографии товара или этапы проекта

Вариант 2: удалить и вставить

Если вы точно знаете значение элемента, можно сделать два обновления: сначала убрать элемент, потом вставить его на нужную позицию

db.lessons.updateOne(
  { _id: lessonId },
  { $pull: { blocks: "practice" } }
)

db.lessons.updateOne(
  { _id: lessonId },
  { $push: { blocks: { $each: ["practice"], $position: 1 } } }
)

Такой подход короче, но есть важный нюанс: между двумя операциями документ уже изменен. Если порядок критичен и несколько пользователей могут менять массив одновременно, лучше использовать транзакцию или одну операцию с пересобранным массивом и проверкой версии документа

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

После обновления перечитайте документ:

db.lessons.findOne(
  { _id: lessonId },
  { blocks: 1 }
)

Проверьте три вещи: элемент остался один раз, он стоит на нужной позиции, остальные элементы не потерялись. Для пользовательского интерфейса полезно хранить не только массив строк, а массив объектов:

blocks: [
  { id: "intro", title: "Вступление" },
  { id: "practice", title: "Практика" }
]

Так вы перемещаете элемент по стабильному id, а не по тексту, который может измениться

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

Перемещают по индексу без проверки

Индекс мог измениться после другого обновления. Сначала найдите элемент по id, затем меняйте порядок

Используют $push, но забывают $each

Для $position нужен $each, даже если вставляете один элемент

Получают повтор элемента

Если сначала не удалить старое значение, $push добавит еще один такой же элемент

Хранят слишком большой массив

Если массив постоянно растет, подумайте об отдельной коллекции с полем position. Так сортировка будет проще и безопаснее

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

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

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

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

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

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

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