MongoDB - это документоориентированная NoSQL база данных, которая хранит данные в формате BSON (бинарный JSON). Вот полная шпаргалка по основным концепциям и командам MongoDB.
- База данных - контейнер для коллекций
- Коллекция - группа документов (аналог таблицы в SQL)
- Документ - набор пар ключ-значение в формате BSON (аналог строки в SQL)
- Поле - пара ключ-значение в документе (аналог столбца в SQL)
- Индекс - специальная структура данных для ускорения запросов
- Строки (
String
) - Числа (
Number
,NumberInt
,NumberLong
,NumberDecimal
) - Булевы значения (
Boolean
) - Массивы (
Array
) - Объекты (
Object
) - Null (
null
) - Дата/время (
Date
) - ObjectId (
ObjectId
) - уникальный идентификатор документа - Двоичные данные (
BinData
) - Регулярные выражения (
RegExp
)
# Локальное подключение
mongo
# Подключение к удаленному серверу
mongo "mongodb://hostname:port/database"
# Подключение с аутентификацией
mongo "mongodb://username:password@hostname:port/database"
// Показать все базы данных
show dbs
// Создать/переключиться на базу данных
use mydatabase
// Показать текущую базу данных
db
// Удалить базу данных
db.dropDatabase()
// Показать все коллекции в текущей БД
show collections
// Создать коллекцию
db.createCollection("users")
// Удалить коллекцию
db.users.drop()
// Вставить один документ
db.users.insertOne({
name: "Иван",
age: 30,
email: "[email protected]"
})
// Вставить несколько документов
db.users.insertMany([
{ name: "Мария", age: 25, email: "[email protected]" },
{ name: "Алексей", age: 35, email: "[email protected]" }
])
// Альтернативный синтаксис (устаревший)
db.users.insert({ name: "Петр", age: 40 })
// Найти все документы в коллекции
db.users.find()
// Найти с форматированием вывода
db.users.find().pretty()
// Найти по условию
db.users.find({ age: 30 })
// Найти по нескольким условиям (AND)
db.users.find({ age: 30, name: "Иван" })
// Найти один документ
db.users.findOne({ name: "Иван" })
// Ограничение полей в результате (1 - включить, 0 - исключить)
db.users.find({}, { name: 1, email: 1, _id: 0 })
// Ограничение количества результатов
db.users.find().limit(5)
// Пропуск результатов (для пагинации)
db.users.find().skip(10).limit(5)
// Сортировка (1 - по возрастанию, -1 - по убыванию)
db.users.find().sort({ age: 1, name: -1 })
// Подсчет документов
db.users.countDocuments({ age: { $gt: 30 } })
// Обновить один документ
db.users.updateOne(
{ name: "Иван" },
{ $set: { age: 31, status: "активен" } }
)
// Обновить несколько документов
db.users.updateMany(
{ age: { $lt: 30 } },
{ $set: { status: "молодой" } }
)
// Заменить весь документ
db.users.replaceOne(
{ name: "Иван" },
{ name: "Иван Петров", age: 31, email: "[email protected]" }
)
// Инкремент числового поля
db.users.updateOne(
{ name: "Иван" },
{ $inc: { age: 1 } }
)
// Добавить элемент в массив
db.users.updateOne(
{ name: "Иван" },
{ $push: { hobbies: "футбол" } }
)
// Удалить элемент из массива
db.users.updateOne(
{ name: "Иван" },
{ $pull: { hobbies: "футбол" } }
)
// Upsert (создать если не существует)
db.users.updateOne(
{ name: "Новый пользователь" },
{ $set: { age: 25 } },
{ upsert: true }
)
// Удалить один документ
db.users.deleteOne({ name: "Иван" })
// Удалить несколько документов
db.users.deleteMany({ age: { $lt: 18 } })
// Удалить все документы
db.users.deleteMany({})
// Равно (=)
db.users.find({ age: 30 })
// Не равно (!=)
db.users.find({ age: { $ne: 30 } })
// Больше чем (>)
db.users.find({ age: { $gt: 30 } })
// Больше или равно (>=)
db.users.find({ age: { $gte: 30 } })
// Меньше чем (<)
db.users.find({ age: { $lt: 30 } })
// Меньше или равно (<=)
db.users.find({ age: { $lte: 30 } })
// В списке значений (IN)
db.users.find({ age: { $in: [25, 30, 35] } })
// Не в списке значений (NOT IN)
db.users.find({ age: { $nin: [25, 30, 35] } })
// И (AND) - можно также использовать запятую между условиями
db.users.find({ $and: [{ age: { $gt: 25 } }, { age: { $lt: 35 } }] })
// ИЛИ (OR)
db.users.find({ $or: [{ age: { $lt: 20 } }, { age: { $gt: 60 } }] })
// НЕ (NOT)
db.users.find({ age: { $not: { $gt: 30 } } })
// И НЕ (NOR)
db.users.find({ $nor: [{ age: 20 }, { name: "Иван" }] })
// Проверка существования поля
db.users.find({ email: { $exists: true } })
// Проверка типа поля
db.users.find({ age: { $type: "number" } })
db.users.find({ age: { $type: 16 } }) // 16 - код для типа Int32
// Точное совпадение массива
db.users.find({ hobbies: ["чтение", "спорт", "музыка"] })
// Содержит элемент
db.users.find({ hobbies: "спорт" })
// Содержит все элементы
db.users.find({ hobbies: { $all: ["спорт", "музыка"] } })
// Размер массива
db.users.find({ hobbies: { $size: 3 } })
// Поиск по элементам массива с условием
db.users.find({ "scores.0": { $gt: 80 } }) // Первый элемент > 80
db.users.find({ scores: { $elemMatch: { $gt: 80, $lt: 90 } } }) // Есть элемент > 80 и < 90
// Установить значение
db.users.updateOne({ name: "Иван" }, { $set: { age: 31 } })
// Удалить поле
db.users.updateOne({ name: "Иван" }, { $unset: { status: "" } })
// Увеличить/уменьшить число
db.users.updateOne({ name: "Иван" }, { $inc: { age: 1 } })
// Умножить число
db.users.updateOne({ name: "Иван" }, { $mul: { salary: 1.1 } }) // Увеличить на 10%
// Минимальное значение (обновляет только если новое значение меньше)
db.users.updateOne({ name: "Иван" }, { $min: { age: 25 } })
// Максимальное значение (обновляет только если новое значение больше)
db.users.updateOne({ name: "Иван" }, { $max: { age: 35 } })
// Переименовать поле
db.users.updateMany({}, { $rename: { "old_field": "new_field" } })
// Добавить в массив
db.users.updateOne({ name: "Иван" }, { $push: { hobbies: "футбол" } })
// Добавить несколько значений в массив
db.users.updateOne(
{ name: "Иван" },
{ $push: { hobbies: { $each: ["футбол", "теннис"] } } }
)
// Добавить уникальные значения в массив
db.users.updateOne(
{ name: "Иван" },
{ $addToSet: { hobbies: "футбол" } }
)
// Удалить из массива
db.users.updateOne({ name: "Иван" }, { $pull: { hobbies: "футбол" } })
// Удалить первый или последний элемент массива
db.users.updateOne({ name: "Иван" }, { $pop: { hobbies: 1 } }) // Последний элемент
db.users.updateOne({ name: "Иван" }, { $pop: { hobbies: -1 } }) // Первый элемент
// Создать простой индекс
db.users.createIndex({ name: 1 }) // 1 - по возрастанию, -1 - по убыванию
// Создать составной индекс
db.users.createIndex({ name: 1, age: -1 })
// Создать уникальный индекс
db.users.createIndex({ email: 1 }, { unique: true })
// Создать индекс с ограниченным временем жизни (TTL)
db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 }) // 1 час
// Создать текстовый индекс
db.articles.createIndex({ title: "text", content: "text" })
// Создать геопространственный индекс
db.places.createIndex({ location: "2dsphere" })
// Создать частичный индекс
db.users.createIndex(
{ email: 1 },
{ partialFilterExpression: { age: { $gt: 18 } } }
)
// Создать индекс с весами для текстового поиска
db.articles.createIndex(
{ title: "text", content: "text" },
{ weights: { title: 10, content: 1 } }
)
// Показать все индексы
db.users.getIndexes()
// Удалить индекс по имени
db.users.dropIndex("name_1")
// Удалить все индексы (кроме _id)
db.users.dropIndexes()
// Перестроить индексы
db.users.reIndex()
// Базовый пример агрегации
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: { _id: "$customer", totalAmount: { $sum: "$amount" } } },
{ $sort: { totalAmount: -1 } }
])
// $match - фильтрация документов (как find)
db.users.aggregate([
{ $match: { age: { $gt: 25 } } }
])
// $project - выбор полей (как проекция в find)
db.users.aggregate([
{ $project: { name: 1, email: 1, _id: 0 } }
])
// $group - группировка документов
db.orders.aggregate([
{ $group: {
_id: "$customer",
count: { $sum: 1 },
totalAmount: { $sum: "$amount" },
avgAmount: { $avg: "$amount" },
minAmount: { $min: "$amount" },
maxAmount: { $max: "$amount" }
}
}
])
// $sort - сортировка
db.users.aggregate([
{ $sort: { age: -1, name: 1 } }
])
// $limit - ограничение количества
db.users.aggregate([
{ $limit: 10 }
])
// $skip - пропуск документов
db.users.aggregate([
{ $skip: 10 }
])
// $unwind - развертывание массива
db.users.aggregate([
{ $unwind: "$hobbies" }
])
// $lookup - объединение коллекций (JOIN)
db.orders.aggregate([
{ $lookup: {
from: "users",
localField: "userId",
foreignField: "_id",
as: "userDetails"
}
}
])
// $addFields - добавление новых полей
db.users.aggregate([
{ $addFields: {
fullName: { $concat: ["$firstName", " ", "$lastName"] },
isAdult: { $gte: ["$age", 18] }
}
}
])
// $count - подсчет документов
db.users.aggregate([
{ $match: { age: { $gt: 30 } } },
{ $count: "adultsCount" }
])
// $facet - параллельные агрегации
db.users.aggregate([
{ $facet: {
"byAge": [
{ $group: { _id: "$age", count: { $sum: 1 } } }
],
"byCity": [
{ $group: { _id: "$city", count: { $sum: 1 } } }
]
}
}
])
// $out - сохранение результата в новую коллекцию
db.orders.aggregate([
{ $group: { _id: "$customer", total: { $sum: "$amount" } } },
{ $out: "customerTotals" }
])
// $merge - слияние результата с существующей коллекцией
db.orders.aggregate([
{ $group: { _id: "$customer", total: { $sum: "$amount" } } },
{ $merge: {
into: "customerStats",
on: "_id",
whenMatched: "merge",
whenNotMatched: "insert"
}
}
])
// Арифметические операторы
db.products.aggregate([
{ $project: {
name: 1,
discountPrice: { $subtract: ["$price", "$discount"] },
priceWithTax: { $multiply: ["$price", 1.2] },
pricePerUnit: { $divide: ["$price", "$quantity"] },
totalCost: { $add: ["$price", "$shipping"] }
}
}
])
// Строковые операторы
db.users.aggregate([
{ $project: {
name: 1,
nameLower: { $toLower: "$name" },
nameUpper: { $toUpper: "$name" },
nameLength: { $strLenCP: "$name" },
firstChar: { $substr: ["$name", 0, 1] },
fullName: { $concat: ["$firstName", " ", "$lastName"] }
}
}
])
// Логические операторы
db.users.aggregate([
{ $project: {
name: 1,
age: 1,
isAdult: { $gte: ["$age", 18] },
ageCategory: {
$cond: {
if: { $lt: ["$age", 18] },
then: "ребенок",
else: {
$cond: {
if: { $lt: ["$age", 65] },
then: "взрослый",
else: "пенсионер"
}
}
}
}
}
}
])
// Операторы для дат
db.orders.aggregate([
{ $project: {
orderDate: 1,
year: { $year: "$orderDate" },
month: { $month: "$orderDate" },
day: { $dayOfMonth: "$orderDate" },
hour: { $hour: "$orderDate" },
dayOfWeek: { $dayOfWeek: "$orderDate" }, // 1 = воскресенье, 7 = суббота
daysSinceOrder: {
$divide: [
{ $subtract: [new Date(), "$orderDate"] },
1000 * 60 * 60 * 24
]
}
}
}
])
// Операторы для массивов
db.users.aggregate([
{ $project: {
name: 1,
hobbies: 1,
hobbyCount: { $size: "$hobbies" },
firstHobby: { $arrayElemAt: ["$hobbies", 0] },
lastHobby: { $arrayElemAt: ["$hobbies", -1] },
hasReading: { $in: ["чтение", "$hobbies"] },
allHobbies: { $reduce: {
input: "$hobbies",
initialValue: "",
in: { $concat: ["$$value", { $cond: [{ $eq: ["$$value", ""] }, "", ", "] }, "$$this"] }
}}
}
}
])
MongoDB поддерживает транзакции с версии 4.0 для реплика-сетов и с версии 4.2 для шардированных кластеров.
// Начать сессию
const session = db.getMongo().startSession();
// Начать транзакцию
session.startTransaction();
try {
// Операции в транзакции
const usersCollection = session.getDatabase("mydatabase").users;
const ordersCollection = session.getDatabase("mydatabase").orders;
usersCollection.updateOne(
{ _id: userId },
{ $inc: { balance: -100 } }
);
ordersCollection.insertOne({
userId: userId,
amount: 100,
status: "completed",
date: new Date()
});
// Если все операции успешны, фиксируем транзакцию
session.commitTransaction();
} catch (error) {
// При ошибке откатываем транзакцию
session.abortTransaction();
print("Ошибка транзакции:", error);
} finally {
// Закрываем сессию
session.endSession();
}
// Создать пользователя
db.createUser({
user: "admin",
pwd: "password",
roles: [{ role: "userAdminAnyDatabase", db: "admin" }]
})
// Добавить роль пользователю
db.grantRolesToUser("admin", [{ role: "readWrite", db: "mydatabase" }])
// Удалить роль у пользователя
db.revokeRolesFromUser("admin", [{ role: "readWrite", db: "mydatabase" }])
// Изменить пароль пользователя
db.changeUserPassword("admin", "newpassword")
// Удалить пользователя
db.dropUser("admin")
// Показать всех пользователей
db.getUsers()
// Показать текущего пользователя
db.runCommand({ connectionStatus: 1 })
-
Встроенные роли для базы данных:
read
- чтение данныхreadWrite
- чтение и запись данныхdbAdmin
- административные операции без доступа к даннымuserAdmin
- управление пользователями и ролямиdbOwner
- комбинация readWrite, dbAdmin и userAdmin
-
Встроенные роли для всех баз данных:
readAnyDatabase
- чтение любой базы данныхreadWriteAnyDatabase
- чтение и запись в любую базу данныхuserAdminAnyDatabase
- управление пользователями в любой базе данныхdbAdminAnyDatabase
- администрирование любой базы данныхroot
- полный доступ ко всему
// Статистика базы данных
db.stats()
// Статистика коллекции
db.users.stats()
// Информация о выполнении запроса
db.users.find({ age: { $gt: 30 } }).explain("executionStats")
// Текущие операции
db.currentOp()
// Убить операцию по ID
db.killOp(opId)
// Статус сервера
db.serverStatus()
// Информация о профилировании
db.getProfilingStatus()
// Настройка профилирования (0 - выкл, 1 - медленные запросы, 2 - все запросы)
db.setProfilingLevel(1, { slowms: 100 })
// Просмотр профилированных запросов
db.system.profile.find().sort({ ts: -1 }).limit(10)
# Создание резервной копии
mongodump --db=mydatabase --out=/backup/mongo
# Восстановление из резервной копии
mongorestore --db=mydatabase /backup/mongo/mydatabase
# Экспорт коллекции в JSON
mongoexport --db=mydatabase --collection=users --out=users.json
# Импорт из JSON
mongoimport --db=mydatabase --collection=users --file=users.json
// Инициализация реплика-сета
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "mongodb0.example.net:27017" },
{ _id: 1, host: "mongodb1.example.net:27017" },
{ _id: 2, host: "mongodb2.example.net:27017" }
]
})
// Статус реплика-сета
rs.status()
// Добавить узел в реплика-сет
rs.add("mongodb3.example.net:27017")
// Удалить узел из реплика-сета
rs.remove("mongodb3.example.net:27017")
// Настроить узел как арбитр (не хранит данные)
rs.addArb("mongodb4.example.net:27017")
// Настройка приоритета узла
cfg = rs.conf()
cfg.members[1].priority = 2
rs.reconfig(cfg)
// Принудительное переключение мастера
rs.stepDown()
// Включение шардинга для базы данных
sh.enableSharding("mydatabase")
// Создание шардированного ключа для коллекции
sh.shardCollection("mydatabase.users", { "userId": "hashed" })
// Статус шардинга
sh.status()
// Добавление шарда
sh.addShard("rs1/mongodb0.example.net:27017")
// Удаление шарда
sh.removeShard("rs1")
// Балансировка шардов
sh.startBalancer()
sh.stopBalancer()
sh.isBalancerRunning()
// Создание 2dsphere индекса
db.places.createIndex({ location: "2dsphere" })
// Поиск мест в радиусе 1000 метров от точки
db.places.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [55.7558, 37.6173] // [долгота, широта]
},
$maxDistance: 1000
}
}
})
// Поиск мест внутри полигона
db.places.find({
location: {
$geoWithin: {
$geometry: {
type: "Polygon",
coordinates: [
[
[55.75, 37.61],
[55.75, 37.62],
[55.76, 37.62],
[55.76, 37.61],
[55.75, 37.61]
]
]
}
}
}
})
// Поиск мест, пересекающихся с полигоном
db.places.find({
location: {
$geoIntersects: {
$geometry: {
type: "Polygon",
coordinates: [/* ... */]
}
}
}
})
// Создание текстового индекса
db.articles.createIndex({ title: "text", content: "text" })
// Простой текстовый поиск
db.articles.find({ $text: { $search: "mongodb nosql" } })
// Текстовый поиск с весами в результатах
db.articles.find(
{ $text: { $search: "mongodb nosql" } },
{ score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } })
// Поиск точной фразы
db.articles.find({ $text: { $search: "\"mongodb database\"" } })
// Исключение слов из поиска
db.articles.find({ $text: { $search: "mongodb -sql" } })
// Создание коллекции с валидацией
db.createCollection("users", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "email", "age"],
properties: {
name: {
bsonType: "string",
description: "Должно быть строкой и обязательно"
},
email: {
bsonType: "string",
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
description: "Должен быть валидным email адресом"
},
age: {
bsonType: "int",
minimum: 18,
maximum: 120,
description: "Должно быть целым числом от 18 до 120"
},
phone: {
bsonType: "string",
description: "Должно быть строкой, если указано"
}
}
}
},
validationLevel: "strict", // strict или moderate
validationAction: "error" // error или warn
})
// Изменение правил валидации
db.runCommand({
collMod: "users",
validator: { /* новая схема */ },
validationLevel: "moderate",
validationAction: "warn"
})
// Открыть поток изменений для коллекции
const changeStream = db.users.watch();
// Итерация по изменениям
while (!changeStream.isExhausted()) {
if (changeStream.hasNext()) {
const change = changeStream.next();
printjson(change);
}
}
// Поток изменений с фильтрацией
const pipeline = [
{ $match: { "operationType": { $in: ["insert", "update"] } } },
{ $match: { "fullDocument.age": { $gte: 18 } } }
];
const filteredStream = db.users.watch(pipeline);
// Возобновление потока изменений с определенного токена
const resumeToken = changeStream.getResumeToken();
const newStream = db.users.watch([], { resumeAfter: resumeToken });
// Создание коллекции со сжатием
db.createCollection("logs", {
storageEngine: {
wiredTiger: {
configString: "block_compressor=zlib"
}
}
})
// Доступные алгоритмы сжатия:
// - none (без сжатия)
// - snappy (по умолчанию, быстрое сжатие)
// - zlib (лучшее сжатие, но медленнее)
// - zstd (с MongoDB 4.2, хороший баланс)
// Создание ограниченной коллекции (с лимитом размера)
db.createCollection("logs", {
capped: true,
size: 1048576, // 1MB максимальный размер
max: 1000 // максимальное количество документов
})
// Проверка, является ли коллекция ограниченной
db.logs.isCapped()
// Преобразование обычной коллекции в ограниченную
db.runCommand({ convertToCapped: "users", size: 10000000 })
// Запрос в обратном порядке (от новых к старым)
db.logs.find().sort({ $natural: -1 })
// Запрос с ожиданием новых документов (как tail -f)
cursor = db.logs.find().addOption(2) // tailable cursor
while (cursor.hasNext()) {
printjson(cursor.next())
}
// Проверка статуса аутентификации
db.runCommand({ getParameter: 1, authenticationMechanisms: 1 })
// Включение только локальных подключений
// В файле mongod.conf:
// net:
// bindIp: 127.0.0.1
// Настройка SSL/TLS
// В файле mongod.conf:
// net:
// ssl:
// mode: requireSSL
// PEMKeyFile: /path/to/mongodb.pem
// CAFile: /path/to/ca.pem
// Просмотр сетевых настроек
db.adminCommand({ getParameter: 1, sslMode: 1 })
// Настройка использования памяти WiredTiger
// В файле mongod.conf:
// storage:
// wiredTiger:
// engineConfig:
// cacheSizeGB: 2
// Проверка текущих настроек кеша
db.serverStatus().wiredTiger.cache
// Статистика использования памяти
db.serverStatus().mem
// Создание GridFS бакета
let bucket = new GridFSBucket(db, {
bucketName: 'files'
});
// Загрузка файла
const fs = require('fs');
const fileId = bucket.openUploadStream('example.pdf', {
metadata: { type: 'pdf', description: 'Пример документа' }
});
fs.createReadStream('/path/to/example.pdf').pipe(fileId);
// Скачивание файла
bucket.openDownloadStreamByName('example.pdf')
.pipe(fs.createWriteStream('/path/to/save/example.pdf'));
// Поиск файлов
db.files.files.find({ "metadata.type": "pdf" })
// Удаление файла
bucket.delete(fileId);
// Простой анализ запроса
db.users.find({ age: { $gt: 30 } }).explain()
// Детальный анализ выполнения
db.users.find({ age: { $gt: 30 } }).explain("executionStats")
// Полный анализ с планами запросов
db.users.find({ age: { $gt: 30 } }).explain("allPlansExecution")
// Анализ агрегации
db.users.aggregate([
{ $match: { age: { $gt: 30 } } },
{ $group: { _id: "$city", count: { $sum: 1 } } }
], { explain: true })
-
Индексы:
- Создавайте индексы для часто используемых полей в запросах
- Используйте составные индексы для запросов с несколькими условиями
- Избегайте создания лишних индексов (они замедляют вставку и обновление)
-
Запросы:
- Используйте проекцию для выборки только нужных полей
- Ограничивайте результаты с помощью limit()
- Используйте покрывающие индексы (все поля запроса в индексе)
-
Структура данных:
- Денормализуйте данные для частых операций чтения
- Используйте вложенные документы вместо соединений
- Избегайте больших массивов в документах
-
Шардинг:
- Выбирайте правильный ключ шардирования
- Распределяйте нагрузку равномерно между шардами
-
Ошибка соединения:
Error: couldn't connect to server
Решение: Проверьте, что MongoDB запущена, порт доступен, и нет проблем с сетью.
-
Ошибка аутентификации:
Authentication failed
Решение: Проверьте имя пользователя и пароль, убедитесь, что пользователь имеет доступ к нужной базе данных.
-
Превышение размера документа:
Document too large
Решение: Документы в MongoDB ограничены 16MB. Разделите большие документы или используйте GridFS для файлов.
-
Дублирование ключа:
E11000 duplicate key error
Решение: Проверьте уникальность полей перед вставкой или используйте upsert с правильными условиями.
-
Медленные запросы: Решение: Проверьте индексы, используйте explain() для анализа, оптимизируйте запросы и структуру данных.
-
Схема "один-ко-многим":
// Вариант 1: Массив в родительском документе (для небольшого количества дочерних элементов) { _id: ObjectId("123"), name: "Иван", addresses: [ { street: "Ленина", city: "Москва" }, { street: "Пушкина", city: "Санкт-Петербург" } ] } // Вариант 2: Ссылка на родителя в дочерних документах (для большого количества) // Коллекция users { _id: ObjectId("123"), name: "Иван" } // Коллекция addresses { _id: ObjectId("a1"), userId: ObjectId("123"), street: "Ленина", city: "Москва" } { _id: ObjectId("a2"), userId: ObjectId("123"), street: "Пушкина", city: "Санкт-Петербург" }
-
Схема "многие-ко-многим":
// Коллекция students { _id: ObjectId("s1"), name: "Иван" } { _id: ObjectId("s2"), name: "Мария" } // Коллекция courses { _id: ObjectId("c1"), name: "Математика" } { _id: ObjectId("c2"), name: "Физика" } // Коллекция enrollments (связующая) { _id: ObjectId("e1"), studentId: ObjectId("s1"), courseId: ObjectId("c1"), grade: "A" } { _id: ObjectId("e2"), studentId: ObjectId("s1"), courseId: ObjectId("c2"), grade: "B" } { _id: ObjectId("e3"), studentId: ObjectId("s2"), courseId: ObjectId("c1"), grade: "A+" }
-
Схема для версионирования:
// Коллекция documents { _id: ObjectId("d1"), title: "Документ", current: ObjectId("v3") } // Коллекция versions { _id: ObjectId("v1"), documentId: ObjectId("d1"), content: "Версия 1", createdAt: ISODate("2023-01-01") } { _id: ObjectId("v2"), documentId: ObjectId("d1"), content: "Версия 2", createdAt: ISODate("2023-01-02") } { _id: ObjectId("v3"), documentId: ObjectId("d1"), content: "Версия 3", createdAt: ISODate("2023-01-03") }
-
Схема для древовидных структур:
// Вариант 1: Родительская ссылка { _id: ObjectId("c1"), name: "Электроника", parentId: null } { _id: ObjectId("c2"), name: "Телефоны", parentId: ObjectId("c1") } // Вариант 2: Путь к предкам (для быстрого поиска всей иерархии) { _id: ObjectId("c1"), name: "Электроника", path: [] } { _id: ObjectId("c2"), name: "Телефоны", path: [ObjectId("c1")] } { _id: ObjectId("c3"), name: "Смартфоны", path: [ObjectId("c1"), ObjectId("c2")] }
-
Схема для временных рядов:
// Вариант 1: Документ на каждое измерение (для детальных данных) { _id: ObjectId("m1"), sensorId: "temp1", value: 22.5, timestamp: ISODate("2023-01-01T12:00:00Z") } // Вариант 2: Массивы значений (для компактности) { _id: ObjectId("s1"), sensorId: "temp1", date: ISODate("2023-01-01"), readings: [ { time: ISODate("2023-01-01T12:00:00Z"), value: 22.5 }, { time: ISODate("2023-01-01T12:15:00Z"), value: 22.7 } ] }
- Транзакции в распределенных системах (с MongoDB 4.2)
- Поля с шифрованием на стороне клиента (с MongoDB 4.2)
- Wildcard индексы (с MongoDB 4.2):
// Индекс для всех полей, начинающихся с "address." db.users.createIndex({ "address.$**": 1 })
- Сжатие Zstandard (с MongoDB 4.2)
- Распределенные транзакции (с MongoDB 4.2)
- Оконные функции в агрегациях (с MongoDB 5.0):
db.sales.aggregate([ { $setWindowFields: { partitionBy: "$region", sortBy: { date: 1 }, output: { cumulativeSum: { $sum: "$amount", window: { documents: ["unbounded", "current"] } } } } } ])
- Временные коллекции (с MongoDB 5.0)
- Улучшенный шардинг (с MongoDB 5.0)
- Улучшенный текстовый поиск (с MongoDB 5.0)
- Улучшенные индексы для массивов (с MongoDB 5.0)
MongoDB - мощная и гибкая NoSQL база данных, которая отлично подходит для работы с большими объемами неструктурированных или полуструктурированных данных. Ее документоориентированная модель позволяет разработчикам быстро создавать и изменять схемы данных, а богатый набор функций, включая агрегации, геопространственные запросы, шардинг и репликацию, делает ее подходящей для широкого спектра приложений.