Управление вложенными документами MongoDB

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

Введение

В этой лабораторной работе вы научитесь эффективно управлять вложенными документами в MongoDB. Вложенные документы (embedded documents, nested documents) являются основной особенностью модели данных MongoDB, позволяющей хранить сложные иерархические данные в одном документе. Вы освоите ряд техник, включая создание документов с вложенными данными, обновление конкретных полей внутри них, удаление элементов и выполнение запросов к этим сложным структурам. Вы также узнаете, как обеспечивать согласованность структуры данных с помощью валидации схемы (schema validation). Эти навыки необходимы для создания надежных и эффективных приложений с использованием MongoDB.

Создание документов с вложенными данными

На этом шаге вы научитесь создавать документы со вложенными структурами в MongoDB. Это фундаментальный навык для моделирования связанных данных в одном документе.

Сначала откройте MongoDB Shell (mongosh), чтобы начать взаимодействие с базой данных. Все последующие команды в этой лабораторной работе будут выполняться в этой оболочке, если не указано иное.

mongosh

Далее переключитесь на новую базу данных с именем bookstore. Если эта база данных не существует, MongoDB создаст ее для вас при первом сохранении данных.

use bookstore

Теперь вы создадите коллекцию с именем books и вставите один документ. Этот документ будет содержать вложенные объекты и массив вложенных объектов, представляющих детали книги.

db.books.insertOne({
    title: "Advanced MongoDB",
    author: {
        name: "Jane Smith",
        contact: {
            email: "jane.smith@example.com",
            phone: "+1-555-123-4567"
        }
    },
    published: {
        year: 2023,
        publisher: "Tech Publications"
    },
    chapters: [
        { number: 1, title: "Introduction to Nested Documents" },
        { number: 2, title: "Advanced Document Structures" }
    ]
})

В документе, который вы только что создали:

  • author и published являются вложенными документами (объектами).
  • Документ author содержит еще один вложенный документ, contact.
  • chapters — это массив, содержащий несколько вложенных документов, каждый из которых представляет главу.

Чтобы просмотреть документ и подтвердить его структуру, используйте метод find().

db.books.find()

Вы должны увидеть следующий вывод, подтверждающий, что документ был вставлен правильно. _id — это уникальный идентификатор, автоматически генерируемый MongoDB.

[
  {
    _id: ObjectId("..."),
    title: 'Advanced MongoDB',
    author: {
      name: 'Jane Smith',
      contact: {
        email: 'jane.smith@example.com',
        phone: '+1-555-123-4567'
      }
    },
    published: {
      year: 2023,
      publisher: 'Tech Publications'
    },
    chapters: [
      { number: 1, title: 'Introduction to Nested Documents' },
      { number: 2, title: 'Advanced Document Structures' }
    ]
  }
]

Обновление вложенных полей и элементов массива

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

Сначала давайте обновим контактную информацию автора. Для этого вы используете оператор $set с точечной нотацией (dot notation), чтобы указать точный путь к полю, которое вы хотите изменить. Эта команда изменит номер телефона и добавит новое поле website.

db.books.updateOne(
    { title: "Advanced MongoDB" },
    { $set: {
        "author.contact.phone": "+1-888-999-0000",
        "author.contact.website": "www.janesmith.com"
    } }
)

Точечная нотация "author.contact.phone" указывает MongoDB перейти в объект author, затем в объект contact и обновить поле phone.

Далее вы добавите новую главу в массив chapters, используя оператор $push.

db.books.updateOne(
    { title: "Advanced MongoDB" },
    { $push: {
        chapters: {
            number: 3,
            title: "MongoDB Advanced Techniques"
        }
    } }
)

Вы также можете обновить конкретный элемент внутри массива. Давайте изменим название первой главы. Мы используем позиционный оператор $ , который действует как заполнитель для первого элемента массива, соответствующего условию запроса ("chapters.number": 1).

db.books.updateOne(
    { title: "Advanced MongoDB", "chapters.number": 1 },
    { $set: {
        "chapters.$.title": "Introduction to Nested Documents (Revised)"
    } }
)

Чтобы проверить все изменения, получите документ снова. Метод .pretty() форматирует вывод для лучшей читаемости.

db.books.find({ title: "Advanced MongoDB" }).pretty()

В выводе будет показан обновленный номер телефона, новый веб-сайт, добавленная третья глава и измененное название первой главы.

Удаление вложенных полей и элементов массива

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

Сначала давайте удалим поле website из контактной информации автора, используя оператор $unset. Значение, передаваемое $unset (в данном случае пустая строка ""), не имеет значения; оператор просто удаляет указанное поле.

db.books.updateOne(
    { title: "Advanced MongoDB" },
    { $unset: { "author.contact.website": "" } }
)

Далее вы удалите элемент из массива. Давайте удалим третью главу (ту, у которой number: 3) из массива chapters, используя оператор $pull. Оператор $pull удаляет все элементы массива, соответствующие указанному условию.

db.books.updateOne(
    { title: "Advanced MongoDB" },
    { $pull: {
        chapters: { number: 3 }
    } }
)

Наконец, вы можете удалить весь вложенный объект. Давайте удалим объект contact из документа author, снова используя оператор $unset.

db.books.updateOne(
    { title: "Advanced MongoDB" },
    { $unset: { "author.contact": "" } }
)

Чтобы увидеть результат этих операций удаления, снова выполните запрос к документу.

db.books.find({ title: "Advanced MongoDB" }).pretty()

В выводе будет показано, что поле website и весь объект contact отсутствуют, а массив chapters теперь содержит только два элемента.

Запрос документов с вложенными данными

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

db.books.drop()

Теперь вставьте несколько новых документов с различными вложенными структурами для практики запросов.

db.books.insertMany([
    {
        title: "MongoDB Essentials",
        author: {
            name: "John Doe",
            experience: { years: 5, specialization: "Database Design" }
        },
        tags: ["beginner", "database", "nosql"],
        chapters: [
            { number: 1, title: "Introduction", pages: 25 },
            { number: 2, title: "Advanced Concepts", pages: 45 }
        ]
    },
    {
        title: "Advanced Database Techniques",
        author: {
            name: "Jane Smith",
            experience: { years: 8, specialization: "Distributed Systems" }
        },
        tags: ["advanced", "distributed", "nosql"],
        chapters: [
            { number: 1, title: "System Design", pages: 35 },
            { number: 2, title: "Performance Optimization", pages: 55 }
        ]
    }
])

Чтобы найти книгу по полю во вложенном документе, используйте точечную нотацию (dot notation). Этот запрос находит книгу, написанную "John Doe".

db.books.find({ "author.name": "John Doe" })

Вы можете углубляться во вложенные структуры. Этот запрос находит книги, в которых специализация автора — "Database Design".

db.books.find({ "author.experience.specialization": "Database Design" })

Чтобы найти документы, где массив содержит определенное значение, вы можете напрямую запрашивать поле массива. Этот запрос находит все книги с тегом "nosql".

db.books.find({ tags: "nosql" })

Вы также можете запрашивать документы, где элемент массива соответствует определенному условию. Этот запрос находит книги, у которых есть хотя бы одна глава объемом более 40 страниц, используя оператор $gt (больше чем).

db.books.find({ "chapters.pages": { $gt: 40 } })

Наконец, вы можете комбинировать несколько условий. Этот запрос находит книги с тегом "advanced", написанные автором с опытом работы 5 лет и более ($gte означает больше или равно).

db.books.find({
    "author.experience.years": { $gte: 5 },
    tags: "advanced"
})

Применение структуры документов с валидацией схемы

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

Сначала создайте новую коллекцию с именем courses. При ее создании вы передадите опцию validator, содержащую правила схемы.

db.createCollection("courses", {
   validator: {
      $jsonSchema: {
         bsonType: "object",
         required: ["title", "instructor", "duration", "topics"],
         properties: {
            title: {
               bsonType: "string",
               description: "must be a string and is required"
            },
            instructor: {
               bsonType: "object",
               required: ["name", "email"],
               properties: {
                  name: { bsonType: "string" },
                  email: {
                     bsonType: "string",
                     pattern: "^.+@.+$"
                  }
               }
            },
            duration: {
               bsonType: "int",
               minimum: 1,
               maximum: 100
            },
            topics: {
               bsonType: "array",
               minItems: 1,
               items: { bsonType: "string" }
            }
         }
      }
   }
})

Эта схема требует, чтобы каждый документ имел поля title, instructor, duration и topics. Она также определяет тип данных для каждого поля, включая вложенные правила для объекта instructor и массива topics.

Теперь попробуйте вставить документ, соответствующий этим правилам. Эта операция должна пройти успешно.

db.courses.insertOne({
   title: "MongoDB Advanced Techniques",
   instructor: {
      name: "Jane Smith",
      email: "jane.smith@example.com"
   },
   duration: 40,
   topics: ["Nested Documents", "Schema Validation"]
})

Далее попытайтесь вставить документ, нарушающий правила схемы. Этот документ имеет неправильный тип данных для instructor.name, недопустимый формат электронной почты, значение duration вне допустимого диапазона и пустой массив topics.

db.courses.insertOne({
   title: "Invalid Course",
   instructor: {
      name: 123,
      email: "invalid-email"
   },
   duration: 200,
   topics: []
})

Эта вставка завершится ошибкой, и MongoDB вернет ошибку Document failed validation (Документ не прошел валидацию). Это предотвращает сохранение несогласованных данных и помогает поддерживать целостность вашей базы данных.

Резюме

В этой лабораторной работе вы изучили основные методы управления вложенными документами в MongoDB. Вы начали с создания документов со сложными вложенными структурами, включая объекты и массивы. Затем вы практиковались в обновлении конкретных полей с использованием точечной нотации (dot notation) и операторов, таких как $set и $push. Вы также узнали, как удалять данные с помощью $unset и $pull. Кроме того, вы исследовали, как выполнять целевые запросы к вложенным данным, и, наконец, как обеспечивать целостность данных путем определения и применения валидатора JSON Schema к коллекции. Эти навыки имеют решающее значение для создания приложений, которые эффективно используют гибкую модель документов MongoDB.