Миграция с 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