Обновление массивов в MongoDB

MongoDBBeginner
Практиковаться сейчас

Введение

В этой лабораторной работе вы научитесь манипулировать массивами в документах MongoDB. Вы попрактикуетесь в добавлении, удалении и обновлении элементов массива с использованием мощных операторов обновления MongoDB. Лабораторная работа содержит пошаговые инструкции и практические примеры, которые помогут вам освоить управление массивами в ваших базах данных MongoDB.

Вы начнете с добавления элементов в массив с помощью оператора $push. Далее вы научитесь удалять элементы с помощью операторов $pull и $pullAll. Вы также узнаете, как изменять конкретные элементы в массиве и как использовать $addToSet для обеспечения того, чтобы массив содержал только уникальные элементы. Наконец, вы научитесь удалять существующие дубликаты из массива с помощью конвейера агрегации (aggregation pipeline).

Добавление элементов в массив с помощью $push

На этом шаге вы научитесь добавлять новые элементы в массив в документе MongoDB с помощью оператора $push. Этот оператор добавляет указанное значение в конец массива.

Сначала откройте оболочку MongoDB (MongoDB shell) для взаимодействия с вашей базой данных. Все операции с базой данных в этой лабораторной работе будут выполняться внутри этой оболочки.

mongosh

Оказавшись в оболочке, переключитесь на базу данных arraylab. Эта база данных была создана для вас в процессе настройки.

use arraylab

Скрипт настройки также создал коллекцию students с одним документом. Найдем этот документ, чтобы увидеть его текущее состояние.

db.students.findOne({ name: "Alice Johnson" })

Вы должны увидеть следующий вывод, который показывает, что Алиса записана на два курса:

{
  _id: ObjectId('...'),
  name: 'Alice Johnson',
  courses: [ 'Mathematics', 'Computer Science' ]
}

Теперь давайте добавим новый курс, "Data Structures", в массив courses Алисы, используя оператор $push.

db.students.updateOne(
    { name: "Alice Johnson" },
    { $push: { courses: "Data Structures" } }
)

Метод updateOne находит документ, соответствующий фильтру { name: "Alice Johnson" }, и применяет обновление { $push: { courses: "Data Structures" } }. Оператор $push добавляет новый курс в массив courses.

Вы также можете добавлять несколько элементов одновременно, комбинируя $push с модификатором $each. Давайте добавим "Physics" и "Chemistry" в массив.

db.students.updateOne(
    { name: "Alice Johnson" },
    { $push: { courses: { $each: ["Physics", "Chemistry"] } } }
)

Чтобы убедиться, что все новые курсы были добавлены, снова выполните команду findOne.

db.students.findOne({ name: "Alice Johnson" })

Обновленный документ теперь содержит все пять курсов:

{
  _id: ObjectId('...'),
  name: 'Alice Johnson',
  courses: [
    'Mathematics',
    'Computer Science',
    'Data Structures',
    'Physics',
    'Chemistry'
  ]
}

Удаление элементов из массива

На этом шаге вы научитесь удалять элементы из массива с помощью операторов $pull и $pullAll. $pull удаляет все вхождения указанного значения, в то время как $pullAll удаляет все вхождения нескольких указанных значений.

Вы должны все еще находиться в оболочке mongosh из предыдущего шага. Давайте начнем с удаления курса "Physics" из списка Алисы с помощью оператора $pull.

db.students.updateOne(
    { name: "Alice Johnson" },
    { $pull: { courses: "Physics" } }
)

Эта команда находит документ для "Alice Johnson" и удаляет строку "Physics" из ее массива courses.

Далее, давайте удалим несколько курсов одновременно. Оператор $pullAll идеально подходит для этого. Мы удалим "Mathematics" и "Chemistry".

db.students.updateOne(
    { name: "Alice Johnson" },
    { $pullAll: { courses: ["Mathematics", "Chemistry"] } }
)

Теперь давайте проверим конечное состояние документа, чтобы увидеть, какие курсы остались.

db.students.findOne({ name: "Alice Johnson" })

Вывод показывает, что "Physics", "Mathematics" и "Chemistry" были удалены, осталось только два курса.

{
  _id: ObjectId('...'),
  name: 'Alice Johnson',
  courses: [ 'Computer Science', 'Data Structures' ]
}

Обновление конкретных элементов в массиве

На этом шаге вы научитесь изменять конкретные элементы внутри массива. Это полезно, когда ваш массив содержит объекты, и вам нужно обновить поле в одном из этих объектов.

Сначала вставим новый документ студента. Массив courses этого документа будет содержать объекты, каждый из которых имеет поля name и grade.

db.students.insertOne({
    name: "Bob Smith",
    courses: [
        { name: "Mathematics", grade: "B" },
        { name: "Computer Science", grade: "A" },
        { name: "Physics", grade: "C" }
    ]
})

Предположим, мы хотим изменить оценку Боба по "Computer Science" с "A" на "A+". Мы можем использовать позиционный оператор $. Этот оператор действует как заполнитель для первого элемента, соответствующего условию запроса.

db.students.updateOne(
    { name: "Bob Smith", "courses.name": "Computer Science" },
    { $set: { "courses.$.grade": "A+" } }
)

В этой команде запрос { "courses.name": "Computer Science" } идентифицирует правильный элемент массива. Затем обновление { $set: { "courses.$.grade": "A+" } } использует $ для ссылки на этот элемент и обновления его поля grade.

Проверим изменение.

db.students.findOne({ name: "Bob Smith" })

Вывод покажет обновленную оценку:

{
  _id: ObjectId('...'),
  name: 'Bob Smith',
  courses: [
    { name: 'Mathematics', grade: 'B' },
    { name: 'Computer Science', grade: 'A+' },
    { name: 'Physics', grade: 'C' }
  ]
}

Вы также можете обновить все элементы массива одновременно, используя оператор позиционирования для всех элементов $[ ]. Давайте добавим поле semester ко всем курсам Боба.

db.students.updateOne(
    { name: "Bob Smith" },
    { $set: { "courses.$[].semester": "Fall 2023" } }
)

Проверьте конечный документ, чтобы увидеть результат.

db.students.findOne({ name: "Bob Smith" })

Все объекты курсов в массиве теперь имеют поле semester.

{
  _id: ObjectId('...'),
  name: 'Bob Smith',
  courses: [
    { name: 'Mathematics', grade: 'B', semester: 'Fall 2023' },
    { name: 'Computer Science', grade: 'A+', semester: 'Fall 2023' },
    { name: 'Physics', grade: 'C', semester: 'Fall 2023' }
  ]
}

Обеспечение уникальности элементов с помощью $addToSet

На этом шаге вы научитесь использовать оператор $addToSet. Этот оператор добавляет элемент в массив только в том случае, если он еще не существует в массиве, тем самым предотвращая дублирование записей.

Сначала добавим нового студента с массивом навыков.

db.students.insertOne({
    name: "Emma Wilson",
    skills: ["Python", "JavaScript"]
})

Теперь попробуем добавить "Python" снова, используя $addToSet. Поскольку "Python" уже есть в массиве, эта операция не изменит документ.

db.students.updateOne(
    { name: "Emma Wilson" },
    { $addToSet: { skills: "Python" } }
)

Проверим документ, чтобы убедиться.

db.students.findOne({ name: "Emma Wilson" })

Вы увидите, что массив skills не изменился, потому что "Python" уже присутствовал.

{
  _id: ObjectId('...'),
  name: 'Emma Wilson',
  skills: [ 'Python', 'JavaScript' ]
}

Как и $push, $addToSet может быть объединен с модификатором $each для добавления нескольких значений. Будут добавлены только те значения, которых еще нет в массиве.

db.students.updateOne(
    { name: "Emma Wilson" },
    { $addToSet: {
        skills: {
            $each: ["React", "Node.js", "Python", "TypeScript"]
        }
    } }
)

Проверим конечный документ.

db.students.findOne({ name: "Emma Wilson" })

Новые, уникальные навыки были добавлены, в то время как дубликат "Python" был проигнорирован.

{
  _id: ObjectId('...'),
  name: 'Emma Wilson',
  skills: [ 'Python', 'JavaScript', 'React', 'Node.js', 'TypeScript' ]
}

Удаление существующих дубликатов из массива

В то время как $addToSet предотвращает добавление новых дубликатов, иногда у вас может быть документ, в котором массив уже содержит повторяющиеся значения. На этом шаге вы узнаете, как удалить существующие дубликаты с помощью конвейера агрегации.

Сначала вставим документ с массивом skills, содержащим дубликаты.

db.students.insertOne({
    name: "Michael Chen",
    skills: ["Python", "JavaScript", "Python", "React", "JavaScript", "Node.js"]
})

Чтобы удалить эти дубликаты, мы можем использовать конвейер агрегации с этапом $merge. Этот конвейер прочитает документ, создаст новый массив с уникальными элементами, а затем обновит исходный документ.

Сначала нам нужно создать индекс по полю name, чтобы операция $merge работала корректно:

db.students.createIndex({ name: 1 }, { unique: true })

Теперь выполните следующую команду агрегации:

db.students.aggregate([
    { $match: { name: "Michael Chen" } },
    { $project: {
        name: 1,
        skills: { $setUnion: "$skills" }
    } },
    { $merge: { into: "students", on: "name", whenMatched: "replace" } }
])

Разберем этот конвейер:

  1. $match: Этот этап фильтрует документы, обрабатывая только документ для "Michael Chen".
  2. $project: Этот этап изменяет структуру документа. Мы сохраняем поле name и заменяем массив skills результатом $setUnion: "$skills". Оператор $setUnion принимает массив и возвращает новый массив, содержащий только уникальные элементы.
  3. $merge: Этот этап записывает результаты конвейера обратно в коллекцию students. Он находит документ для обновления на основе поля name (on: "name") и заменяет весь документ новым из конвейера (whenMatched: "replace"). Созданный нами индекс обеспечивает эффективное сопоставление и обновление.

Теперь проверим, были ли удалены дубликаты.

db.students.findOne({ name: "Michael Chen" })

В выводе будет показан массив skills только с уникальными элементами. Порядок элементов может отличаться.

{
  _id: ObjectId('...'),
  name: 'Michael Chen',
  skills: [ 'JavaScript', 'Node.js', 'Python', 'React' ]
}

Резюме

В этой лабораторной работе вы изучили несколько основных методов управления массивами в MongoDB. Вы практиковались в добавлении элементов с помощью $push, их удалении с помощью $pull и $pullAll, а также в обновлении конкретных элементов с использованием позиционного оператора $. Вы также узнали, как поддерживать уникальные элементы в массиве с помощью $addToSet и как удалять существующие дубликаты с помощью конвейера агрегации с $setUnion и $merge. Эти навыки являются основополагающими для создания динамичных и надежных приложений с использованием MongoDB.