Узнайте, как активизировать MongoDB или Mongoose с помощью нескольких приемов.
В прошлом году, где-то под Рождество, я начал свой путь разработчика NodeJS с MongoDB. Я знаю в начале. Я сделал много ошибок новичка и провел много часов в StackOverflow и GitHub, чтобы найти подходящее решение. После нескольких изнурительных переживаний. Я нахожу небольшие, но очень полезные уловки в MongoDB или мангусте.
1. худой ()
Когда вы выполняете любой запрос в mongoose до получения результата, mongoose выполняет hydrate()
модельную функцию, которая используется для создания нового документа из существующих необработанных данных, предварительно сохраненных в БД. Возвращенный документ является экземпляром класса Mongoose Document
, который очень тяжелый, потому что у него много внутреннего состояния для отслеживания изменений. lean()
создайте ярлык из функцииhydrate()
и выполняйте запросы быстрее и с меньшим объемом памяти, но возвращаемые документы представляют собой обычные старые объекты JavaScript (POJO), а не документы мангуста.
// Module that estimates the size of an object in memory
const sizeof = require('object-sizeof');
const normalDoc = await MyModel.findOne();
// To enable the `lean` option for a query, use the `lean()` function.
const leanDoc = await MyModel.findOne().lean();
sizeof(normalDoc); // >= 1000
sizeof(leanDoc); // 86, 10x smaller!
2. Виртуальная собственность
Некоторые из нас уже знакомы с виртуальной собственностью мангуста. Но вот какое-то скрытое поведение virtual. По сути, virtual - это просто вычисляемое свойство документов MongoDB, которые не хранятся в MongoDB.
Предположим, у вас есть два строковых свойства: firstName и lastName. Вы можете создать виртуальное свойство fullName, которое позволит вам установить оба этих свойства одновременно.
const userSchema = mongoose.Schema({ firstName: String, lastName: String });
// Create a virtual property `fullName`. userSchema.virtual('fullName').get(function() { return `${this.firstName} $(this.lastName}`; }); const User = mongoose.model('User', userSchema); let doc = await User.create({ firstName: 'Tim', lastName: 'Burton' });
// `fullName` is now a property on documents. doc.fullName; // 'Tim Burton'
Mongoose не включает виртуальные файлы при преобразовании документа в JSON или POJO. Это означает, что виртуальных машин не будет, если вы используете .lean()
. Например, если вы передадите документ в функцию Экспресс res.json()
, виртуальные файлы не будут включены по умолчанию. Если вы хотите получить виртуальную res.json()
, просто установите для параметра схемы toJSON
значение {virtuals: true}
.
const userSchema = mongoose.Schema({
firstName: String,
lastName: String
}, { toJSON: {virtuals: true} });
3. Индексы ()
Я был удивлен, когда прочитал о функциональности индекса MongoDB. Вы можете сравнить индекс MongoDB с индексами SQL, оба они почти одинаковы. Мы можем определить эти индексы в нашей схеме на уровне пути или на уровне схемы. Определение индексов на уровне схемы необходимо при создании составных индексов.
Индексы поддерживают эффективное выполнение запросов в MongoDB. Без индексов MongoDB должен выполнить сканирование коллекции, то есть сканировать каждый документ в коллекции, чтобы выбрать те документы, которые соответствуют запросу запроса. Если для запроса существует соответствующий индекс, MongoDB может использовать этот индекс, чтобы ограничить количество документов, которые необходимо проверить.
const userSchema= new Schema({
name: String,
email: { type: [String], index: true } // field level
});
userSchema.index({ email: 1, name: -1 }); // schema level
Примечание. индексы используют комбинацию памяти и временных файлов на диске для завершения построения индекса, ограничение на использование памяти по умолчанию составляет 200 мегабайт (для версий 4.2.3 и более поздних) и 500 (для версий 4.2.2 и ранее). Вы можете переопределить ограничение памяти, установив параметр сервера maxIndexBuildMemoryUsageMegabytes
.
4. sort ()
Я знаю, что функция sort () довольно распространена в MongoDB, но здесь я говорю о предоставлении дополнительных возможностей функции sort (). Если вы знаете, что sort () по умолчанию дает результаты путем сортировки с учетом регистра. Думаю, очень немногие читатели знали о collation
параметрах в MongoDB. collation
позволяет пользователям указывать правила для конкретного языка для сравнения строк, такие как правила для регистра букв и знаков ударения.
User.find().collation({locale:'en',strength: 1}).sort({username:1}) .then( (users) =>{ //do your stuff }); // sort by username without case sensitivity.
UserSchema.index( {username:1}, {collation: { locale: 'en', strength: 1}} ); //
index onusername
without case sensitivity.
Здесь locale: 'en'
показывает, что коллекция находится на английском языке, а strength: 1
показывает, что сопоставление выполняет сравнение только основных символов, игнорируя другие различия, такие как диакритические знаки и регистр. Кроме того, collation
есть еще несколько параметров, которые вы можете изучить.
5. Методы экземпляра
В MongoDB документы в основном представляют собой небольшие экземпляры реальной модели. MongoDB богат встроенными методами экземпляра. Кроме того, MongoDB предоставляет настраиваемые методы экземпляра документа. Эти методы будут иметь доступ к объекту модели, и их можно будет использовать весьма творчески.
// Define `getFullName` instance method. userSchema.methods.getFullName = function() { return 'Mr.' + this.firstName+ ' ' + this.lastName } // This method accessible via a model instance. let model = new UserModel({ firstName: 'Thomas', lastName: 'Anderson' }) let initials = model.getFullName(); console.log(initials) // This will output: Mr. Thomas Anderson
Примечание. Не объявляйте методы с помощью стрелочных функций ES6 (=>
). Стрелочные функции явно предотвращают привязку this.
Таким образом, ваш метод не будет иметь доступ к документу, и приведенные выше примеры работать не будут.
6. Статические методы
Статические методы аналогичны методам экземпляра, но разница лишь в том, что statics
методы, определенные в модели. С другой стороны, methods
определены в документе (экземпляре). statics
ключевое слово определяет статический метод. Давайте создадим getAllUser
статический метод для получения всех пользовательских данных из базы данных.
userSchema.statics.getAllUsers = function() { return new Promise((resolve, reject) => { this.find((err, docs) => { if(err) { console.error(err) return reject(err) } resolve(docs) }) }) }
С getAllUsers
статикой класс модели возвращает все пользовательские данные из базы данных, вызывая эту статику.
UserModel.getAllUsers() .then(docs => { console.log(docs) }) .catch(err => { console.error(err) })
По моему мнению, вы должны использовать методыstatics
вместо того, чтобы повторять один и тот же запрос несколько раз. Добавление экземпляров и статических методов - хороший подход для реализации интерфейса для взаимодействия с базой данных в коллекциях и записях.
7. Промежуточное ПО
Промежуточное ПО используется для управления определенным этапом конвейера. В Mongoose есть 4 типа промежуточного программного обеспечения: промежуточное программное обеспечение для документов, промежуточное программное обеспечение для моделей, агрегированное промежуточное программное обеспечение и промежуточное программное обеспечение для запросов.
Например, в моделях есть функции pre
и post
, которые принимают два параметра:
- Тип события («инициализация», «проверка», «сохранение», «удаление»)
- Обратный вызов, который выполняется с помощью this путем ссылки на экземпляр модели.
Давайте создадим userSchema
с адресом электронной почты и паролем.
const userSchema= new Schema({
email: {
type: String,
unique: true // `email` must be unique
},
password: String
});
Предварительный крючок:
Что делать, если вы хотите всегда сохранять пароль в зашифрованном виде. Для этого одно из решений - вам нужно вручную зашифровать пароль перед сохранением, а другое решение - mongoose, которое поможет вам зашифровать поле пароля перед сохранением в базе данных. pre
ловушка будет обрабатывать вашу логику промежуточного программного обеспечения.
userSchema.pre('save', function (next) {
this.password = hashPassword(this.password)
; // Replace with encrypted password
// Call the next function in the pre-save chain
next();
})
Если возникнут какие-либо ошибки до перехвата, mongoose не выполнит последующее промежуточное ПО или перехваченную функцию. Вместо этого Mongoose передаст ошибку обратному вызову и / или отклонит возвращенное обещание.
Почтовый крючок
Промежуточное ПО Post hook запускается между базой данных и ответом на запрос. Это поможет вам управлять результатом запроса перед его отправкой в конечную точку. Возьмем еще один пример. Наш userSchema
говорит, что поле электронной почты уникально. Но когда вы пытаетесь сохранить это электронное письмо, которое уже хранится в базе данных, MongoDB отправляет ошибку, и мгновенно падает ваш сервер узла. Вам нужно снова перезапустить приложение узла.
Чтобы спасти ваш сервер узла от сбоя, обработчик post берет на себя ответственность за обработку ошибок и пытается сохранить работающий сервер.
userSchema.post('save', function(error, doc, next) {
if (error.name === 'MongoError' && error.code === 11000) {
next(new Error('There was a duplicate key error'));
} else {
next();
}
});
Заключение
Теперь я уверен, что теперь никто не может недооценивать ваши грубые навыки в MongoDB и никогда не пытаться называть вас новичком в этой области. Я просто стараюсь охватить те функциональные возможности, которые будут вам полезны, и сделать ваш код более быстрым и оптимизированным. Мы едва коснулись поверхности, исследуя некоторые возможности Mongoose. Это богатая библиотека, полная полезных и мощных функций. Получайте удовольствие от кодирования.