Узнайте, как активизировать 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 on username 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, которые принимают два параметра:

  1. Тип события («инициализация», «проверка», «сохранение», «удаление»)
  2. Обратный вызов, который выполняется с помощью 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. Это богатая библиотека, полная полезных и мощных функций. Получайте удовольствие от кодирования.