Разность Mongoose между.save() и использованием update()
Чтобы изменить поле в существующей записи в мангусте, в чем разница между использованием
model = new Model([...])
model.field = 'new value';
model.save();
и это
Model.update({[...]}, {$set: {field: 'new value'});
Причина, по которой я задаю этот вопрос, заключается в том, что кто-то предложил проблему, которую я опубликовал вчера: NodeJS и Mongo - Неожиданное поведение, когда несколько пользователей отправляют запросы одновременно. Человек предложил использовать обновление вместо сохранения, и я еще не совсем уверен, почему это изменит ситуацию.
Благодарю!
Ответы
Ответ 1
Сначала две концепции. Ваша заявка - Клиент, Mongodb - Сервер.
Основное различие заключается в том, что с .save()
вас уже есть объект в коде на стороне клиента или ему нужно было получить данные с сервера до того, как вы его запишете, и вы все это напишете.
С другой стороны. .update()
не требует, чтобы данные загружались клиенту с сервера. Все взаимодействие происходит на стороне сервера без получения клиентом. .update()
образом, .update()
может быть очень эффективным при добавлении контента в существующие документы.
Кроме того, существует multi
параметр .update()
который позволяет выполнять действия над более чем одним документом, который соответствует условию запроса.
Есть некоторые вещи в методах удобства, которые вы теряете при использовании .update()
в качестве вызова, но преимущества для определенных операций - это "компромисс", который вы должны нести. Для получения дополнительной информации об этом и доступных вариантах см. Документацию.
Короче .save()
- интерфейс на стороне клиента, .update()
- серверная.
Ответ 2
Некоторые отличия:
- Как отмечалось в другом месте,
update
более эффективно, чем find
за которым следует save
поскольку оно позволяет избежать загрузки всего документа. -
update
Mongoose переводится в update
MongoDB, но save
Mongoose конвертируется либо в insert
MongoDB (для нового документа), либо в update
. - Важно отметить, что при
save
Mongoose внутренне различает документ и отправляет только те поля, которые действительно изменились. Это полезно для атомарности. - По умолчанию проверка не выполняется при
update
но она может быть включена. - API промежуточного программного обеспечения (
pre
и post
hooks) отличается.
Ответ 3
Существует полезная функция на Mongoose под названием Middleware. Есть промежуточное ПО "pre" и "post". Средство выполняется, когда вы выполняете "сохранение", но не во время "обновления". Например, если вы хотите хешировать пароль в схеме пользователя каждый раз, когда пароль изменяется, вы можете использовать pre, чтобы сделать это следующим образом. Другим полезным примером является установка lastModified для каждого документа. Документацию можно найти по адресу http://mongoosejs.com/docs/middleware.html.
UserSchema.pre('save', function(next) {
var user = this;
// only hash the password if it has been modified (or is new)
if (!user.isModified('password')) {
console.log('password not modified');
return next();
}
console.log('password modified');
// generate a salt
bcrypt.genSalt(10, function(err, salt) {
if (err) {
return next(err);
}
// hash the password along with our new salt
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) {
return next(err);
}
// override the cleartext password with the hashed one
user.password = hash;
next();
});
});
});
Ответ 4
Одна деталь, которую не стоит воспринимать легкомысленно: параллелизм
Как упоминалось ранее, при выполнении doc.save()
необходимо сначала загрузить документ в память, затем изменить его и, наконец, doc.save()
внести изменения в сервер MongoDB.
Проблема возникает, когда документ редактируется таким образом одновременно:
- Человек А загружает документ (v1)
- Человек B загружает документ (v1)
- Пользователь B сохраняет изменения в документе (теперь это v2)
- Пользователь A сохраняет изменения в устаревшем (v1) документе
- Человек A увидит, как Mongoose выдаст ошибку VersionError, поскольку документ изменился с момента последней загрузки из коллекции
Параллельность не является проблемой при выполнении атомарных операций, таких как Model.updateOne()
, потому что операция полностью выполняется на сервере MongoDB, который выполняет определенную степень управления параллелизмом.
Поэтому будьте осторожны!