Введение
В этой лабораторной работе вы научитесь использовать проекцию MongoDB для управления тем, какие поля отображаются в результатах ваших запросов. Проекция — это мощная функция, которая позволяет выбирать конкретные поля для возврата, что может уменьшить объем данных, передаваемых по сети, и повысить производительность запросов. Вы попрактикуетесь в включении и исключении полей, проецировании полей во вложенных документах и использовании фреймворка агрегации для изменения выходных данных. К концу этой лабораторной работы вы будете иметь твердое представление о том, как эффективно использовать проекцию в ваших запросах MongoDB.
Выбор конкретных полей с помощью проекции
На этом первом шаге вы изучите основы проекции, выбирая только те конкретные поля, которые вы хотите видеть в результатах запроса. Это известно как "включающая" проекция.
Сначала откройте MongoDB Shell. Этот интерактивный интерфейс командной строки — место, где вы будете выполнять все команды базы данных для этой лабораторной работы.
mongosh
Теперь вы находитесь в MongoDB Shell. Приглашение вашего терминала изменится, указывая на то, что вы подключены. Давайте переключимся на новую базу данных с именем projectlab_database и вставим некоторые примеры данных. Если база данных не существует, MongoDB создаст ее для вас при первом сохранении данных.
use projectlab_database
Далее вставьте три документа в коллекцию с именем users.
db.users.insertMany([
{
name: "John Doe",
age: 30,
email: "john.doe@example.com",
city: "New York",
job: "Software Engineer"
},
{
name: "Jane Smith",
age: 28,
email: "jane.smith@example.com",
city: "San Francisco",
job: "Data Scientist"
},
{
name: "Mike Johnson",
age: 35,
email: "mike.johnson@example.com",
city: "Chicago",
job: "Product Manager"
}
]);
Теперь давайте выполним запрос к этой коллекции. Чтобы вернуть только поля name и age для всех документов, добавьте документ проекции в качестве второго аргумента методу find(). В документе проекции вы указываете поля для включения значением 1. По умолчанию поле _id всегда возвращается. Вы можете явно исключить его, установив его значение в 0.
db.users.find({}, { name: 1, age: 1, _id: 0 });
Вы должны увидеть следующий вывод, который содержит только поля name и age для каждого пользователя:
[
{ "name": "John Doe", "age": 30 },
{ "name": "Jane Smith", "age": 28 },
{ "name": "Mike Johnson", "age": 35 }
]
Этот метод очень полезен для получения только необходимых данных, что особенно важно при работе с большими документами.
Исключение конкретных полей из результатов
Помимо выбора полей для включения, вы также можете указать, какие поля исключить. Это известно как "исключающая" проекция и полезно, когда вы хотите видеть большинство полей, но скрыть некоторые, например, конфиденциальные или большие.
Вы все еще должны находиться в оболочке mongosh с выбранной базой данных projectlab_database.
Чтобы исключить поля, установите их значение в 0 в документе проекции. Давайте выполним запрос для получения всех данных пользователей, но исключим поля email и city.
db.users.find({}, { email: 0, city: 0 });
Вывод будет включать все поля, кроме email и city. Обратите внимание, что поле _id по умолчанию все еще включено.
[
{
_id: ObjectId("..."),
name: 'John Doe',
age: 30,
job: 'Software Engineer'
},
{
_id: ObjectId("..."),
name: 'Jane Smith',
age: 28,
job: 'Data Scientist'
},
{
_id: ObjectId("..."),
name: 'Mike Johnson',
age: 35,
job: 'Product Manager'
}
]
Ключевое правило в проекции заключается в том, что вы не можете смешивать включение (1) и исключение (0) в одном документе проекции. Единственным исключением из этого правила является поле _id. Вы можете явно исключить поле _id (_id: 0), даже включая другие поля, как вы делали на предыдущем шаге. Вы также можете исключить его в исключающей проекции.
Например, чтобы исключить email, city и _id, выполните следующее:
db.users.find({}, { email: 0, city: 0, _id: 0 });
Этот запрос возвращает документы, содержащие только поля name, age и job.
Проекция полей во вложенных документах
Реальные данные часто структурированы с использованием вложенных документов и массивов. Возможности проекции MongoDB позволяют точно выбирать поля, даже если они глубоко встроены в структуру документа.
Сначала очистим существующую коллекцию users и вставим новые документы, которые имеют вложенный объект contact и массив skills.
db.users.deleteMany({});
Теперь вставим новые данные.
db.users.insertMany([
{
name: "John Doe",
contact: {
email: "john.doe@example.com",
phone: {
mobile: "123-456-7890",
work: "987-654-3210"
}
},
skills: ["JavaScript", "MongoDB", "React"]
},
{
name: "Jane Smith",
contact: {
email: "jane.smith@example.com",
phone: {
mobile: "234-567-8901",
work: "876-543-2109"
}
},
skills: ["Python", "Data Science", "Machine Learning"]
}
]);
Для проекции поля внутри вложенного документа используйте "точечную нотацию" (dot notation). Например, чтобы выбрать name пользователя и его номер мобильного телефона, вы укажете "contact.phone.mobile": 1. Давайте попробуем спроецировать name, email и номер мобильного телефона.
db.users.find(
{},
{
name: 1,
"contact.email": 1,
"contact.phone.mobile": 1,
_id: 0
}
);
Результат сохранит вложенную структуру для выбранных полей:
[
{
"name": "John Doe",
"contact": {
"email": "john.doe@example.com",
"phone": { "mobile": "123-456-7890" }
}
},
{
"name": "Jane Smith",
"contact": {
"email": "jane.smith@example.com",
"phone": { "mobile": "234-567-8901" }
}
}
]
Вы также можете спроецировать часть массива, используя оператор $slice. Чтобы получить name и только первые два навыка для каждого пользователя, выполните следующую команду:
db.users.find({}, { name: 1, skills: { $slice: 2 }, _id: 0 });
Вывод покажет каждого пользователя с массивом skills, содержащим только два элемента:
[
{ "name": "John Doe", "skills": ["JavaScript", "MongoDB"] },
{ "name": "Jane Smith", "skills": ["Python", "Data Science"] }
]
Изменение выходных полей с помощью агрегации
Для более сложных преобразований, таких как переименование полей или создание новых вычисляемых полей, проекции метода find() недостаточно. Вместо этого вы можете использовать фреймворк агрегации, в частности стадию $project.
Подготовим наши данные для этого шага. Очистим коллекцию и вставим пользователей с информацией о зарплате.
db.users.deleteMany({});
db.users.insertMany([
{
name: "John Doe",
age: 30,
salary: 75000,
department: "Engineering"
},
{
name: "Jane Smith",
age: 28,
salary: 85000,
department: "Data Science"
},
{
name: "Mike Johnson",
age: 35,
salary: 95000,
department: "Management"
}
]);
Стадия $project в конвейере агрегации может изменять структуру документов, добавляя новые поля, переименовывая существующие или удаляя поля. Чтобы использовать ее, вы передаете массив стадий методу aggregate().
Чтобы переименовать поле, вы определяете новое имя поля и присваиваете ему значение существующего поля, предваряя его знаком $. Давайте переименуем name в fullName и age в yearsOld.
db.users.aggregate([
{
$project: {
fullName: "$name",
yearsOld: "$age",
_id: 0
}
}
]);
Вы также можете создавать новые поля на основе вычислений. Давайте создадим поле monthlySalary, разделив годовую salary на 12, и поле salaryTier на основе условной логики с использованием оператора $switch.
db.users.aggregate([
{
$project: {
name: 1,
monthlySalary: { $divide: ["$salary", 12] },
salaryTier: {
$switch: {
branches: [
{ case: { $lt: ["$salary", 80000] }, then: "Junior" },
{ case: { $gte: ["$salary", 80000] }, then: "Senior" }
],
default: "Unknown"
}
},
_id: 0
}
}
]);
Вывод будет представлять собой совершенно новую структуру документа, которую вы определили на стадии $project:
[
{ "name": "John Doe", "monthlySalary": 6250, "salaryTier": "Junior" },
{
"name": "Jane Smith",
"monthlySalary": 7083.333333333333,
"salaryTier": "Senior"
},
{
"name": "Mike Johnson",
"monthlySalary": 7916.666666666667,
"salaryTier": "Senior"
}
]
Стадия $project дает вам полный контроль над конечной формой результатов вашего запроса, позволяя выполнять мощные преобразования данных непосредственно в базе данных.
Резюме
В этой лабораторной работе вы научились эффективно управлять выводом запросов MongoDB с помощью проекции. Вы начали с основ включения и исключения полей с помощью метода find(). Затем вы перешли к более продвинутым темам, таким как использование точечной нотации для проекции полей во вложенных документах и оператора $slice для возврата подмножества массива. Наконец, вы изучили возможности стадии $project фреймворка агрегации для полного изменения структуры документов путем переименования полей, создания новых вычисляемых полей и применения условной логики. Эти навыки являются основополагающими для написания эффективных и точных запросов в MongoDB.

