Spec-Zone.ru › Mongoose

Миграция с 4.x на 5.x

Обратите внимание: мы планируем прекратить поддержку Mongoose 5 с 1 марта 2024 года. Пожалуйста, ознакомьтесь с нашим руководством по поддержке версий.

Существуют несколько несовместимых изменений, о которых следует помнить при миграции с Mongoose 4.x на Mongoose 5.x.

Если вы все еще используете Mongoose 3.x, пожалуйста, прочитайте руководство по миграции с Mongoose 3.x на 4.x.

  • Требования к версии
  • Средства обработки запросов
  • Обещания и обратные вызовы для mongoose.connect()
  • Логика подключения и useMongoClient
  • Порядок установщиков
  • Проверка, является ли путь заполненным
  • Возвращаемые значения для remove() и deleteX()
  • Курсоры агрегации
  • geoNear
  • Требуемое кодирование URI строк подключения
  • Пароли, содержащие определенные символы
  • Сокеты домена
  • toObject() параметры
  • Параметры агрегации
  • Преобразование в булевы значения
  • Преобразование запросов
  • Управление потоком хуков пост сохранения
  • Оператор $pushAll
  • Использование только прямого порядка ключей
  • Выполнение установщиков для запросов
  • Предварительно скомпилированный пакет для браузера
  • Ошибки сохранения
  • Подписи хуков инициализации
  • numAffected и save()
  • remove() и отложенное выполнение
  • getPromiseConstructor()
  • Передача параметров от предварительных хуков
  • required валидатор для массивов
  • Вывод отладки по умолчанию выводится в stdout вместо stderr
  • Перезапись свойств фильтра
  • bulkWrite() результаты
  • Строгая проверка SSL

Требования к версии

Mongoose теперь требует Node.js >= 4.0.0 и MongoDB >= 3.0.0. MongoDB 2.6 и Node.js < 4 оба прекратили поддержку в 2016 году.

Средства обработки запросов

Средства обработки запросов теперь компилируются при вызове mongoose.model() или db.model(). Если вы добавите обработчик запросов после вызова mongoose.model(), этот обработчик не будет вызван.

const schema = new Schema({ name: String });
const MyModel = mongoose.model('Test', schema);
schema.pre('find', () => { console.log('find!'); });

MyModel.find().exec(function() {
  // In mongoose 4.x, the above `.find()` will print "find!"
  // In mongoose 5.x, "find!" will **not** be printed.
  // Call `pre('find')` **before** calling `mongoose.model()` to make the middleware apply.
});

Обещания и обратные вызовы для mongoose.connect()

mongoose.connect() и mongoose.disconnect() теперь возвращают обещание, если не указан обратный вызов, или null в противном случае. Это не возвращает синглтон mongoose.

// Worked in mongoose 4. Does **not** work in mongoose 5, `mongoose.connect()`
// now returns a promise consistently. This is to avoid the horrible things
// we've done to allow mongoose to be a thenable that resolves to itself.
mongoose.connect('mongodb://127.0.0.1:27017/test').model('Test', new Schema({}));

// Do this instead
mongoose.connect('mongodb://127.0.0.1:27017/test');
mongoose.model('Test', new Schema({}));

Логика подключения и useMongoClient

Опция useMongoClient была удалена в Mongoose 5, теперь она всегда true. Вследствие этого, Mongoose 5 больше не поддерживает несколько подписей функций для mongoose.connect(), которые работали в Mongoose 4.x, если опция useMongoClient была выключена. Ниже приведены примеры вызовов mongoose.connect(), которые не работают в Mongoose 5.x.

  • mongoose.connect('127.0.0.1', 27017);
  • mongoose.connect('127.0.0.1', 'mydb', 27017);
  • mongoose.connect('mongodb://host1:27017,mongodb://host2:27017');

В Mongoose 5.x первый параметр для mongoose.connect() и mongoose.createConnection(), если указан, должен быть строкой подключения к MongoDB. Строка подключения и параметры передаются в функцию MongoClient.connect() драйвера MongoDB Node.js. Mongoose не изменяет строку подключения, хотя mongoose.connect() и mongoose.createConnection() поддерживают несколько дополнительных параметров помимо поддерживаемых драйвером MongoDB.

Порядок установщиков

Установщики выполняются в обратном порядке в 4.x:

const schema = new Schema({ name: String });
schema.path('name').
  set(() => console.log('This will print 2nd')).
  set(() => console.log('This will print first'));

В 5.x установщики выполняются в том порядке, в котором они объявлены.

const schema = new Schema({ name: String });
schema.path('name').
  set(() => console.log('This will print first')).
  set(() => console.log('This will print 2nd'));

Проверка, является ли путь заполненным

Mongoose 5.1.0 представил установщик _id для ObjectIds, который позволяет получить ObjectId независимо от того, заполнен ли путь.

const blogPostSchema = new Schema({
  title: String,
  author: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Author'
  }
});
const BlogPost = mongoose.model('BlogPost', blogPostSchema);

await BlogPost.create({ title: 'test', author: author._id });
const blogPost = await BlogPost.findOne();

console.log(blogPost.author); // '5b207f84e8061d1d2711b421'
// New in Mongoose 5.1.0: this will print '5b207f84e8061d1d2711b421' as well
console.log(blogPost.author._id);

await blogPost.populate('author');
console.log(blogPost.author._id); // '5b207f84e8061d1d2711b421'

Вследствие этого, проверка того, blogPost.author._id является более не приемлема как способ проверки, является ли author заполненным. Используйте blogPost.populated('author') != null или blogPost.author instanceof mongoose.Types.ObjectId для проверки, является ли author заполненным вместо этого.

Обратите внимание, что вы можете вызвать mongoose.set('objectIdGetter', false) для изменения этого поведения.

Возвращаемые значения для remove() и deleteX()

deleteOne(), deleteMany(), и remove() теперь возвращают объект результата, а не весь объект драйвера WriteOpResult.

// In 4.x, this is how you got the number of documents deleted
MyModel.deleteMany().then(res => console.log(res.result.n));
// In 5.x this is how you get the number of documents deleted
MyModel.deleteMany().then(res => res.n);

Курсоры агрегации

Опция useMongooseAggCursor из 4.x теперь всегда включена. Это новый синтаксис для курсоров агрегации в mongoose 5:

// When you call `.cursor()`, `.exec()` will now return a mongoose aggregation
// cursor.
const cursor = MyModel.aggregate([{ $match: { name: 'Val' } }]).cursor().exec();
// No need to `await` on the cursor or wait for a promise to resolve
cursor.eachAsync(doc => console.log(doc));

// Can also pass options to `cursor()`
const cursorWithOptions = MyModel.
  aggregate([{ $match: { name: 'Val' } }]).
  cursor({ batchSize: 10 }).
  exec();

geoNear

Model.geoNear() был удален, потому что драйвер MongoDB больше его не поддерживает

Требуемое кодирование URI строк подключения

Из-за изменений в драйвере MongoDB строки подключения должны быть закодированы в URI.

Если это не так, соединения могут завершиться с сообщением об ошибке некорректного символа.

Пароли, содержащие определенные символы

См. полный список затронутых символов.

Если ваше приложение используется множеством различных строк подключения, возможно, ваши тестовые случаи пройдут, но пароли в продакшене могут не сработать. Кодируйте все строки подключения для безопасности.

Если вы хотите продолжать использовать строки подключения без кодирования, самый простой способ — использовать модуль mongodb-uri, чтобы разобрать строки подключения, а затем создать правильные закодированные версии. Вы можете использовать такую функцию:

const uriFormat = require('mongodb-uri');
function encodeMongoURI(urlString) {
  if (urlString) {
    const parsed = uriFormat.parse(urlString);
    urlString = uriFormat.format(parsed);
  }
  return urlString;
}

// Your un-encoded string.
const mongodbConnectString = 'mongodb://...';
mongoose.connect(encodeMongoURI(mongodbConnectString));

Функция выше безопасна для использования, независимо от того, уже закодирована существующая строка или нет.

Сокеты домена

Сокеты домена должны быть закодированы в URI. Например:

// Works in mongoose 4. Does **not** work in mongoose 5 because of more
// stringent URI parsing.
const host = '/tmp/mongodb-27017.sock';
mongoose.createConnection(`mongodb://aaron:psw@${host}/fake`);

// Do this instead
const host = encodeURIComponent('/tmp/mongodb-27017.sock');
mongoose.createConnection(`mongodb://aaron:psw@${host}/fake`);

toObject() Параметры

Параметр options для toObject() и toJSON() объединяет значения по умолчанию, а не перезаписывает их.

// Note the `toObject` option below
const schema = new Schema({ name: String }, { toObject: { virtuals: true } });
schema.virtual('answer').get(() => 42);
const MyModel = db.model('MyModel', schema);

const doc = new MyModel({ name: 'test' });
// In mongoose 4.x this prints "undefined", because `{ minimize: false }`
// overwrites the entire schema-defined options object.
// In mongoose 5.x this prints "42", because `{ minimize: false }` gets
// merged with the schema-defined options.
console.log(doc.toJSON({ minimize: false }).answer);

Параметры агрегации

aggregate() больше не принимает разброс, вы должны передать свой агрегационный pipeline как массив. Следующий код работал в 4.x:

MyModel.aggregate({ $match: { isDeleted: false } }, { $skip: 10 }).exec(cb);

Вышеприведенный код не работает в 5.x, вы должны заключить стадии $match и $skip в массив.

MyModel.aggregate([{ $match: { isDeleted: false } }, { $skip: 10 }]).exec(cb);

Преобразование в булевы значения

По умолчанию, mongoose 4 преобразует любое значение в булево без ошибок.

// Fine in mongoose 4, would save a doc with `boolField = true`
const MyModel = mongoose.model('Test', new Schema({
  boolField: Boolean
}));

MyModel.create({ boolField: 'not a boolean' });

Mongoose 5 преобразует только следующие значения в true:

  • true
  • 'true'
  • 1
  • '1'
  • 'yes'

А следующие значения в false:

  • false
  • 'false'
  • 0
  • '0'
  • 'no'

Все остальные значения приведут к CastError

Преобразование запросов

Преобразование для update(), updateOne(), updateMany(), replaceOne(), remove(), deleteOne(), и deleteMany() происходит только при exec(). Это упрощает модификацию данных хуками и пользовательскими помощниками запросов, так как mongoose не перестроит данные, которые вы передали, до тех пор, пока не будут выполнены ваши хуки и помощники запросов. Это также позволяет установить параметр overwrite *после* передачи обновления.

// In mongoose 4.x, this becomes `{ $set: { name: 'Baz' } }` despite the `overwrite`
// In mongoose 5.x, this overwrite is respected and the first document with
// `name = 'Bar'` will be replaced with `{ name: 'Baz' }`
User.where({ name: 'Bar' }).update({ name: 'Baz' }).setOptions({ overwrite: true });

Управление потоком хуков пост сохранения

Хуки пост сохранения теперь получают управление потоком, что означает, что асинхронные хуки пост сохранения и хуки пост сохранения дочерних документов выполняются до вашего обратного вызова save().

const ChildModelSchema = new mongoose.Schema({
  text: {
    type: String
  }
});
ChildModelSchema.post('save', function(doc) {
  // In mongoose 5.x this will print **before** the `console.log()`
  // in the `save()` callback. In mongoose 4.x this was reversed.
  console.log('Child post save');
});
const ParentModelSchema = new mongoose.Schema({
  children: [ChildModelSchema]
});

const Model = mongoose.model('Parent', ParentModelSchema);
const m = new Model({ children: [{ text: 'test' }] });
m.save(function() {
  // In mongoose 5.xm this prints **after** the "Child post save" message.
  console.log('Save callback');
});

Оператор $pushAll

$pushAll больше не поддерживается и больше не используется внутри save(), так как он был устаревшим с MongoDB 2.4. Используйте $push с $each вместо этого.

Использование только прямого порядка ключей

Опция retainKeyOrder была удалена, mongoose теперь всегда сохраняет то же положение ключа при клонировании объектов. Если у вас есть запросы или индексы, которые зависят от обратного порядка ключей, вам придется их изменить.

Выполнение установщиков для запросов

Установщики теперь выполняются по запросам по умолчанию, а старая опция runSettersOnQuery была удалена.

const schema = new Schema({
  email: { type: String, lowercase: true }
});
const Model = mongoose.model('Test', schema);
Model.find({ email: 'FOO@BAR.BAZ' }); // Converted to `find({ email: 'foo@bar.baz' })`

Предварительно скомпилированный пакет для браузера

Мы больше не предоставляем предварительно скомпилированную версию mongoose для браузера. Если вы хотите использовать схемы mongoose в браузере, вам нужно создать собственный пакет с помощью browserify/webpack.

Ошибки сохранения

Опция saveErrorIfNotFound была удалена, mongoose теперь всегда генерирует ошибку из save() если базовый документ не найден

Подписи хуков инициализации

Хуки init теперь полностью синхронны и не получают next() в качестве параметра.

Document.prototype.init() больше не принимает обратный вызов в качестве параметра. Он всегда был синхронным, просто имел обратный вызов по причинам совместимости.

numAffected и save()

doc.save() больше не передает numAffected в качестве 3-го параметра в свой обратный вызов.

remove() и отжатие

doc.remove() больше не отжимается

getPromiseConstructor()

getPromiseConstructor() отсутствует, используйте просто mongoose.Promise.

Передача параметров из предварительных хуков

Вы не можете передавать параметры следующему предварительному средству обработки в цепочке, используя next() в mongoose 5.x. В mongoose 4, next('Test') в предварительном средстве обработки вызовет следующее средство обработки с параметром «Test». Mongoose 5.x удалил поддержку этого.

required валидатор для массивов

В mongoose 5 required валидатор проверяет только, является ли значение массивом. То есть он не будет вызывать ошибку для пустых массивов, как это происходило в mongoose 4.

вывод отладки по умолчанию выводится в stdout, а не в stderr

В mongoose 5 функция отладки по умолчанию использует console.info() для отображения сообщений вместо console.error().

Перезапись свойств фильтра

В Mongoose 4.x перезапись свойства фильтра, являющегося примитивным типом, объектом, будет молча игнорироваться. Например, следующий код проигнорирует where() и будет эквивалентен Sport.find({ name: 'baseball' })

Sport.find({ name: 'baseball' }).where({ name: { $ne: 'softball' } });

В Mongoose 5.x вышеприведенный код правильно перезапишет 'baseball' на { $ne: 'softball' }

bulkWrite() результаты

Mongoose 5.x использует версию 3.x драйвера MongoDB Node.js . Драйвер MongoDB 3.x изменил формат результата вызовов bulkWrite(), поэтому больше нет свойств верхнего уровня nInserted, nModified, и т.д. Новая структура объекта результата описана здесь.

const Model = mongoose.model('Test', new Schema({ name: String }));

const res = await Model.bulkWrite([{ insertOne: { document: { name: 'test' } } }]);

console.log(res);

В Mongoose 4.x вышеуказанное выведет:

BulkWriteResult {
  ok: [Getter],
  nInserted: [Getter],
  nUpserted: [Getter],
  nMatched: [Getter],
  nModified: [Getter],
  nRemoved: [Getter],
  getInsertedIds: [Function],
  getUpsertedIds: [Function],
  getUpsertedIdAt: [Function],
  getRawResponse: [Function],
  hasWriteErrors: [Function],
  getWriteErrorCount: [Function],
  getWriteErrorAt: [Function],
  getWriteErrors: [Function],
  getLastOp: [Function],
  getWriteConcernError: [Function],
  toJSON: [Function],
  toString: [Function],
  isOk: [Function],
  insertedCount: 1,
  matchedCount: 0,
  modifiedCount: 0,
  deletedCount: 0,
  upsertedCount: 0,
  upsertedIds: {},
  insertedIds: { '0': 5be9a3101638a066702a0d38 },
  n: 1 }

В Mongoose 5.x скрипт выведет:

BulkWriteResult {
  result: 
  { ok: 1,
    writeErrors: [],
    writeConcernErrors: [],
    insertedIds: [ [Object] ],
    nInserted: 1,
    nUpserted: 0,
    nMatched: 0,
    nModified: 0,
    nRemoved: 0,
    upserted: [],
    lastOp: { ts: [Object], t: 1 } },
  insertedCount: 1,
  matchedCount: 0,
  modifiedCount: 0,
  deletedCount: 0,
  upsertedCount: 0,
  upsertedIds: {},
  insertedIds: { '0': 5be9a1c87decfc6443dd9f18 },
  n: 1 }

Строгая валидация SSL

Последние версии драйвера MongoDB Node.js используют строгую валидацию SSL по умолчанию, что может привести к ошибкам, если вы используете самозаверенные сертификаты.

Если это препятствует обновлению, вы можете установить параметр tlsInsecure на значение true.

mongoose.connect(uri, { tlsInsecure: false }); // Opt out of additional SSL validation

© 2010 LearnBoost
Licensed under the MIT License.
https://mongoosejs.com/docs/migrating_to_5.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API