背景
在前端开发过程中,常常需要使用到 MongoDB 数据库。而在 Node.js 中,最常用的 MongoDB 驱动是 Mongoose。在使用 Mongoose 的过程中,我们经常会遇到一些问题,其中一个比较常见的问题就是,当我们指定了默认值后,无法在更新文档时正确地更新相关字段。
问题
我们在使用 Mongoose 插入文档时,可以设置默认值,例如:
const userSchema = new mongoose.Schema({ name: { type: String, default: 'New User' }, age: { type: Number, default: 18 }, });
在上面的代码中,我们为 name
和 age
两个字段设置了默认值,其中 name
的默认值为 'New User'
,age
的默认值为 18
。当我们插入一条新的用户记录时,如果没有设置 name
或 age
,那么 Mongoose 会自动将其设为默认值。
例如,我们插入一条记录:
const user = new User({ name: 'John' }); await user.save();
由于我们只设置了 name
,而没有设置 age
,因此在插入记录时,age
的值将被自动设为 18
,因为这是我们在定义 schema 时设置的默认值。
但是,如果我们尝试更新这个记录,例如将 age
的值改为 20
,我们会发现更新并没有生效:
await User.updateOne({ name: 'John' }, { age: 20 });
通过上面的代码,我们本来希望将 age
的值从 18
修改为 20
,但实际上数据库中该记录的 age
字段仍然为 18
,没有发生变化。
原因
这是因为 Mongoose 在执行更新操作时,默认情况下会跳过默认值。也就是说,即使我们在更新操作中明确地指定了某个字段的值,如果该字段在定义 schema 时有默认值,Mongoose 也不会将更新后的值保存到数据库中。
解决方法
要解决这个问题,我们需要手动对默认值进行覆盖。具体来说,我们可以使用 lean()
方法获取纯 JavaScript 对象(plain JavaScript object),然后手动合并更新操作中的值和默认值,最后将合并后的值保存回数据库中。
下面是示例代码:
const oldUser = await User.findOne({ name: 'John' }).lean(); const updatedUser = _.assign({}, oldUser, { age: 20 }); const result = await User.updateOne({ name: 'John' }, updatedUser);
上面的代码中,我们使用了 Lodash 库的 assign()
方法来合并默认值和更新值。首先,我们通过 findOne()
方法获取符合条件的单个文档,然后使用 lean()
方法将其转换为纯 JavaScript 对象。接着,我们使用 assign()
方法将更新操作中的新值合并到旧的文档对象中,最后使用 updateOne()
方法将合并后的文档保存回数据库中。
值得注意的是,由于 lean()
方法返回的是纯 JavaScript 对象,因此需要手动调用 save()
方法将更新后的值保存回数据库中。如果我们不使用 lean()
方法,直接调用 updateOne()
方法,虽然会返回更新操作的结果,但是数据库中的值却不会发生变化。
总结
在使用 Mongoose 进行 MongoDB 开发时,如果定义了默认值,并且在进行更新操作时发现无法更新一些字段,我们应该手动对默认值进行覆盖,以确保更新操作能够生效。同时,我们需要注意,当使用 lean()
方法获取纯 JavaScript 对象后,必须手动调用 save()
方法才能将更新后的值保存回数据库中。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/653ce5c47d4982a6eb6d9b90