Разность 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, который выполняет определенную степень управления параллелизмом.

Поэтому будьте осторожны!