Mongoose – библиотека моделирования объектов (ODM) для MongoDB и Node.js. Он управляет отношениями между данными, обеспечивает проверку схемы и используется для перевода между объектами в коде и представлении этих объектов в MongoDB.
MongoDB – это база данных документов NoSQL схемы. Это означает, что вы можете хранить в нем документы JSON, а структура этих документов может варьироваться в зависимости от того, что она не применялась как базы данных SQL. Это одно из преимуществ использования NoSQL, поскольку он ускоряет разработку приложений и уменьшает сложность развертываний.
Ниже приведен пример того, как данные хранятся в базе данных Mongo против SQL:
Терминологии
Коллекции
«Коллекции» в Монго эквивалентны таблицам в реляционных базах данных. Они могут проводить несколько документов JSON.
Документы
«Документы» эквивалентны записям или строкам данных в SQL. В то время как строка SQL может ссылаться на данные в других таблицах, документы Mongo обычно объединяются в документе.
Полей
«Поля» или атрибуты похожи на столбцы в таблице SQL.
Схема
Хотя MongoDB является схемой, SQL определяет схему через определение таблицы. Схема Mongoose ‘- это структура данных документов (или форма документа), которая применяется через уровень приложений.
Модели
«Модели» – более высокие конструкции, которые принимают схему и создают экземпляр документа, эквивалентного записей в реляционной базе данных.
Начиная
Монго Установка
Прежде чем мы начнем, давайте настроим Mongo. Вы можете выбрать из один из следующих вариантов (Мы используем вариант № 1 для этой статьи):
- Загрузите соответствующую версию MongoDB для вашей операционной системы от Сайт MongoDB и следуйте их инструкциям по установке
- Создать бесплатную базу данных песочницы Подписка на MLAB.
- Установите Mongo, используя Docker Если вы предпочитаете использовать Docker
Давайте перемещаемся через некоторые основы Mongoose, внедряя модель, которая представляет данные для упрощенной адресной книги.
Я использую код Visual Studio, Node 8,9 и NPM 5.6. Выпусти свой любимый IDE, создайте пустой проект, и давайте начнем! Мы будем использовать синтаксис ограничения ES6 в узле, поэтому мы не будем настроить Babel.
Установка NPM
Пойдем в папку Project и инициализируйте наш проект
npm init -y
Давайте установим Mongoose и библиотеку проверки со следующей командой:
npm install mongoose validator
Приведенная выше команда установки установит последнюю версию библиотек. Синтаксис мангуста в этой статье специфичен для Mongoose V5 и за его пределами.
Соединение с базой данных
Создать файл ./src/database.js под корнем проекта.
Далее мы добавим простой класс с помощью метода, который подключается к базе данных.
Ваша строка подключения будет варьироваться в зависимости от вашей установки.
let mongoose = require('mongoose'); const server = '127.0.0.1:27017'; // REPLACE WITH YOUR DB SERVER const database = 'fcc-Mail'; // REPLACE WITH YOUR DB NAME class Database { constructor() { this._connect() } _connect() { mongoose.connect(`mongodb://${server}/${database}`) .then(() => { console.log('Database connection successful') }) .catch(err => { console.error('Database connection error') }) } } module.exports = new Database()
Выше требуемый («Mongoose») выше возвращает объект Singleton. Это означает, что при первом вызове требуется («Mongoose»), он создает экземпляр класса Mongoose и возвращает его. При последующих вызовах он вернется тот же экземпляр, который был создан и вернулся к вам в первый раз из-за того, как модуль импорт/экспорт работает в ES6.
Точно так же мы превратили в себя класс базы данных в Singleton, вернув экземпляр класса в заявлении Module.exports, потому что нам нужно только одно подключение к базе данных.
ES6 позволяет нам очень легко создать шаблон Singleton (единый экземпляр) из-за того, как модуль загрузчик работает, кэшируя ответ ранее импортированного файла.
Схема мангусты против модели
Модель мангусты – это обертка на схеме мангусты. Схема мангусты определяет структуру документа, значений по умолчанию, валидаторам и т. Д., В то время как модель Mongoose обеспечивает интерфейс к базе данных для создания, запроса, обновления, удаления записей и т. Д.
Создание модели Mongoose содержит в основном из трех частей:
1. Ссылающийся мангуст
let mongoose = require('mongoose')
Эта ссылка будет такой же, как тот, который был возвращен, когда мы подключились к базе данных, что означает, что определения схемы и модели не должны явно подключаться к базе данных.
2. Определение схемы
Схема определяет свойства документов через объект, где имя ключа соответствует имени свойства в коллекции.
let emailSchema = new mongoose.Schema({ email: String })
Здесь мы определяем недвижимость под названием Email С типом схемы Строка Какие отображения внутреннего валидатора будут срабатываться, когда модель сохраняется в базе данных. Он не удается, если тип данных значения не является типом строки.
Допускаются следующие типы схемы:
- Множество
- Логический
- Буфер
- Дата
- Смешанный (общий/гибкий тип данных)
- Число
- Объект
- Нить
Смешанные и объекты определяются при требовании («мангуст»). Schema.Types.
3. Экспорт модели
Нам нужно позвонить модель Constructor на экземпляре Mongoose и пропустите его имя коллекции и ссылку на определение схемы.
module.exports = mongoose.model('Email', emailSchema)
Давайте комбинируем вышеуказанный код в ./src/models/email.js Чтобы определить содержимое базовой модели электронной почты:
let mongoose = require('mongoose') let emailSchema = new mongoose.Schema({ email: String }) module.exports = mongoose.model('Email', emailSchema)
Определение схемы должно быть простым, но его сложность обычно основана на требованиях к применению. Схемы могут быть повторно использованы, и они также могут содержать несколько детских схем. В приведенном выше примере значение свойства электронной почты – это простой тип значения. Однако это также может быть типом объекта с дополнительными свойствами на нем.
Мы можем создать экземпляр модели, который мы определены выше и заполните его, используя следующий синтаксис:
let EmailModel = require('./email') let msg = new EmailModel({ email: 'ada.lovelace@gmail.com' })
Давайте улучшим схему электронной почты, чтобы сделать свойство электронной почты уникальным, обязательным полем и преобразовывать значение в нижний регистр, прежде чем сохранить его. Мы также можем добавить функцию проверки, которая гарантирует, что значение является действительным адресом электронной почты. Мы будем ссылаться и использовать библиотеку валидатора, установленную ранее.
let mongoose = require('mongoose') let validator = require('validator') let emailSchema = new mongoose.Schema({ email: { type: String, required: true, unique: true, lowercase: true, validate: (value) => { return validator.isEmail(value) } } }) module.exports = mongoose.model('Email', emailSchema)
Основные операции
Mongoose имеет гибкую API и обеспечивает множество способов выполнения задачи. Мы не будем сосредоточиться на вариациях, потому что это не имеет возможности для этой статьи, но помните, что большинство операций могут быть выполнены более чем в одном случае синтаксически, либо через архитектуру приложения.
Создать запись
Давайте создадим экземпляр модели электронной почты и сохранить его в базе данных:
let EmailModel = require('./email') let msg = new EmailModel({ email: 'ADA.LOVELACE@GMAIL.COM' }) msg.save() .then(doc => { console.log(doc) }) .catch(err => { console.error(err) })
Результатом является документ, который возвращается после успешного сохранения:
{ _id: 5a78fe3e2f44ba8f85a2409a, email: 'ada.lovelace@gmail.com', __v: 0 }
Возвращены следующие поля (внутренние поля префиксированы с подчеркиванием):
- Поле _ID автоматически генерируется Mongo и является первичным ключом коллекции. Его значение является уникальным идентификатором для документа.
- Значение поля электронной почты возвращается. Обратите внимание, что оно ниже кожура, потому что мы указали строчные буквы: истинный атрибут в схеме.
- __V – это свойство версии, установленные на каждом документе при первом создании Mongoose. Его стоимость содержит внутреннюю версию документа.
Если вы попытаетесь повторить операцию сохранения выше, вы получите ошибку, потому что мы указали, что поле электронной почты должно быть уникальным.
Запись записи
Давайте постараемся получить запись, которую мы сохранили в базе данных ранее. Класс модели обнажает несколько статических и экземпляров методов для выполнения операций в базе данных. Теперь мы постараемся найти запись, которую мы создали ранее, используя метод поиска и передайте электронную почту как поисковый термин.
EmailModel .find({ email: 'ada.lovelace@gmail.com' // search query }) .then(doc => { console.log(doc) }) .catch(err => { console.error(err) })
Возвращенный документ будет похоже на то, что было отображено, когда мы создали запись:
{ _id: 5a78fe3e2f44ba8f85a2409a, email: 'ada.lovelace@gmail.com', __v: 0 }
Обновить запись
Давайте изменим запись выше, изменив адрес электронной почты и добавив другое поле к нему, все в одном операции. Для причин эффективности Mongoose не будет возвращать обновленный документ, поэтому нам нужно пройти дополнительный параметр, чтобы задать его:
EmailModel .findOneAndUpdate( { email: 'ada.lovelace@gmail.com' // search query }, { email: 'theoutlander@live.com' // field:values to update }, { new: true, // return updated doc runValidators: true // validate before update }) .then(doc => { console.log(doc) }) .catch(err => { console.error(err) })
Возвращенный документ будет содержать обновленное письмо:
{ _id: 5a78fe3e2f44ba8f85a2409a, email: 'theoutlander@live.com', __v: 0 }
Удалить запись
Мы будем использовать вызов YinkoneanDremove, чтобы удалить запись. Он возвращает исходный документ, который был удален:
EmailModel .findOneAndRemove({ email: 'theoutlander@live.com' }) .then(response => { console.log(response) }) .catch(err => { console.error(err) })
Помощники
Мы посмотрели на некоторые из основных функциональных возможностей, известных как Crud (Create, Read, Update, Deletete), но Mongoose также предоставляет возможность настроить несколько типов методов и свойств помощника. Они могут быть использованы для дальнейшего упрощения работы с данными.
Давайте создадим пользовательскую схему ./src/models/user.js С помощью fieldfirstname и фамилия:
let mongoose = require('mongoose') let userSchema = new mongoose.Schema({ firstName: String, lastName: String }) module.exports = mongoose.model('User', userSchema)
Виртуальная собственность
Виртуальное свойство не сохраняется в базе данных. Мы можем добавить его в нашу схему в качестве помощника, чтобы получить и устанавливать значения.
Давайте создадим виртуальную недвижимость под названием Funnname, которое можно использовать для установки значений на FirstName и LastName и получить их в качестве комбинированного значения при чтении:
userSchema.virtual('fullName').get(function() { return this.firstName + ' ' + this.lastName }) userSchema.virtual('fullName').set(function(name) { let str = name.split(' ') this.firstName = str[0] this.lastName = str[1] })
Обратные вызовы для Get и Set должны использовать ключевое слово «Функция», поскольку нам нужно получить доступ к модели через это ключевое слово. Использование функций стрелки жира изменит то, что это относится к.
Теперь мы можем установить имя и фамилия, назначая значение Funnname:
let model = new UserModel() model.fullName = 'Thomas Anderson' console.log(model.toJSON()) // Output model fields as JSON console.log() console.log(model.fullName) // Output the full name
Код выше будет выведен следующее:
{ _id: 5a7a4248550ebb9fafd898cf, firstName: 'Thomas', lastName: 'Anderson' } Thomas Anderson
Методы экземпляра
Мы можем создавать пользовательские помощники на схеме и получить доступ к ним через экземпляр модели. Эти методы будут иметь доступ к объекту модели, и их можно использовать довольно творчески. Например, мы могли бы создать метод, чтобы найти всех людей, которые имеют то же имя, что и текущий экземпляр.
В этом примере давайте создадим функцию для возврата инициалов для текущего пользователя. Давайте добавим пользовательский помощник метода под названием GetInitials к схеме:
userSchema.methods.getInitials = function() { return this.firstName[0] + this.lastName[0] }
Этот метод будет доступен через экземпляр модели:
let model = new UserModel({ firstName: 'Thomas', lastName: 'Anderson' }) let initials = model.getInitials() console.log(initials) // This will output: TA
Статические методы
Похоже на методы экземпляра, мы можем создавать статические методы на схеме. Давайте создадим метод для извлечения всех пользователей в базе данных:
userSchema.statics.getUsers = function() { return new Promise((resolve, reject) => { this.find((err, docs) => { if(err) { console.error(err) return reject(err) } resolve(docs) }) }) }
Вызов GetUsers в классе модели вернет всех пользователей в базе данных:
UserModel.getUsers() .then(docs => { console.log(docs) }) .catch(err => { console.error(err) })
Добавление экземпляров и статических методов – это хороший подход для реализации интерфейса для взаимодействия баз данных на коллекциях и записях.
Промежуточное программное обеспечение
Промежуточное программное обеспечение – это функции, работающие на определенных этапах трубопровода. Mongoose поддерживает промежуточное ПО для следующих операций:
- Совокупность
- Документ
- Модель
- Запрос
Например, модели имеют Pre и Post Функции, которые принимают два параметра:
- Тип события («init», «Validate», «Сохранить», «Удалить»)
- Обратный вызов, который выполнен с это ссылается на экземпляр модели
Давайте попробуем пример, добавив два поля, называемые созданным созданным и обновленным в нашу схему:
let mongoose = require('mongoose') let userSchema = new mongoose.Schema({ firstName: String, lastName: String, createdAt: Date, updatedAt: Date }) module.exports = mongoose.model('User', userSchema)
Когда называется Model.Save (), имеется предварительно («Сохранение», …) и Post («Сохранение», …), которое срабатывает. Для второго параметра вы можете пройти функцию, которая вызывается, когда событие срабатывает. Эти функции принимают параметр к следующей функции в цепочке промежуточного программного обеспечения.
Давайте добавим предварительно сохранить крюк и устанавливать значения для создания и обновления:
userSchema.pre('save', function (next) { let now = Date.now() this.updatedAt = now // Set a value for createdAt only if it is null if (!this.createdAt) { this.createdAt = now } // Call the next function in the pre-save chain next() })
Давайте создадим и сохранить нашу модель:
let UserModel = require('./user') let model = new UserModel({ fullName: 'Thomas Anderson' } msg.save() .then(doc => { console.log(doc) }) .catch(err => { console.error(err) })
Вы должны увидеть значения для создания и обновления, когда печатается запись, которая будет напечатана:
{ _id: 5a7bbbeebc3b49cb919da675, firstName: 'Thomas', lastName: 'Anderson', updatedAt: 2018-02-08T02:54:38.888Z, createdAt: 2018-02-08T02:54:38.888Z, __v: 0 }
Плагины
Предположим, что мы хотим отслеживать, когда запись была создана и последняя обновлена в каждой коллекции в нашей базе данных. Вместо повторения вышеуказанного процесса мы можем создать плагин и применить его к каждой схеме.
Давайте создадим файл ./src/model/plugins/timestamp.js и повторить вышеуказанную функциональность в виде модуля многоразового использования:
module.exports = function timestamp(schema) { // Add the two fields to the schema schema.add({ createdAt: Date, updatedAt: Date }) // Create a pre-save hook schema.pre('save', function (next) { let now = Date.now() this.updatedAt = now // Set a value for createdAt only if it is null if (!this.createdAt) { this.createdAt = now } // Call the next function in the pre-save chain next() }) }
Чтобы использовать этот плагин, мы просто передаем его схемыми, которые следует указать эту функциональность:
let timestampPlugin = require('./plugins/timestamp') emailSchema.plugin(timestampPlugin) userSchema.plugin(timestampPlugin)
Запрос здания
Mongoose имеет очень богатый API, который обрабатывает множество сложных операций, поддерживаемых MongoDB. Рассмотрим запрос, в котором мы можем постепенно построить компоненты запроса.
В этом примере мы собираемся:
- Найти все пользователи
- Пропустить первые 100 записей
- Ограничить результаты 10 записей
- Сортировать результаты по именному поле имени
- Выберите первый случай
- Выполнить этот запрос
UserModel.find() // find all users .skip(100) // skip the first 100 items .limit(10) // limit to 10 items .sort({firstName: 1} // sort ascending by firstName .select({firstName: true} // select firstName only .exec() // execute the query .then(docs => { console.log(docs) }) .catch(err => { console.error(err) })
Закрытие
Мы едва поцарапали поверхность, исследуя некоторые возможности мангусты. Это богатая библиотека, полная полезных и мощных функций, которые делают его радости работать с моделями данных в уровне приложений.
Хотя вы можете взаимодействовать с Mongo непосредственно с помощью драйвера Mongo, Mongoose упростит это взаимодействие, позволяя вам моделировать отношения между данными и легко подтверждать их.
Забавный факт: Мангуст создается Валерий Карпов Кто невероятно талантливый инженер! Он придумал термин Средний стек Отказ
Нажмите здесь для моего предстоящего курса: полные разработчики Руководство по Mongoose