在使用 Mongoose 进行 MongoDB 的数据操作时,我们经常会遇到更新嵌套数组的情况。然而,有时候在更新时,我们会遇到 $setOnInsert 操作未生效的问题,引起了一些困惑。本文旨在探究这个问题的原因,并提供如何解决这个问题的方法,让你写出更加规范的代码。
问题的出现
通常情况下,我们可以通过一条简单的 Mongoose 语句来实现嵌套数组的更新操作:
Model.updateOne({ _id: id }, { $push: { array: newItem } });
上述语句会在名为 array 的嵌套数组中新增一个元素。然而,Mongoose 提供了更多的操作符和方法来管理嵌套数组中的元素,例如 $addToSet、$pull 和 $pop 等等。其中,我们尤其需要关注 $setOnInsert 操作符。
$setOnInsert 操作符可以在插入文档时,向文档中插入指定的值。例如:
Model.updateOne({ _id: id }, { $setOnInsert: { createdAt: new Date() } });
以上语句会在插入新的文档时,自动插入一个名为 createdAt 的字段并赋值为当前时间。这就是 $setOnInsert 的基本用法。
问题的原因
然而,当我们在更新嵌套数组时,使用以下代码时出现了问题:
Model.updateOne({ _id: id, 'array.id': itemId }, { $setOnInsert: { 'array.$.createdAt': new Date() } }, { upsert: true });
上述代码意在在嵌套数组中找到一个名为 id 的元素,并为它新增名为 createdAt 的字段,并将它指定的值设置为当前时间。但是,我们会发现,在执行以上这个语句后,$setOnInsert 并没有按照预期的方式被执行。
这是由于 Mongoose 在嵌套数组中的 $setOnInsert 操作时,会将新的元素的属性都设置为初始化值,而不是当前操作中指定的值。因此,$setOnInsert 操作中的值不会被正确地更新到新的元素中去。
解决方案
为了解决这个问题,我们需要采用其他的方法来更新嵌套数组。以下是两种解决方案:
方案一:使用 $each 和 $position
通过使用 $each 和 $position 操作符,我们可以强制 MongoDB 在插入新元素时使用预期的值。以下是代码示例:
Model.update({ _id: id }, { $push: { array: { $each: [{ id: itemId, createdAt: new Date() }], $position: 0 } } });
上述代码将在 array 末尾创建一个新的元素,该元素具有指定的 createdAt 属性。
方案二:使用 findOneAndUpdate
另一个解决方案是使用 findOneAndUpdate 方法。该方法可让我们一条语句中完成更新和插入操作。以下是代码示例:
-- -------------------- ---- ------- ------------------------ ---- --- ----------- ------ -- - ----- - -------------------- --- ------ -- ------------- - ------------- ------ - -- - ------- ----- ---- ---- -- ----- ---- -- - -- ------ ---
通过使用 $set 和 $setOnInsert,我们可以在同一语句中更新和插入数据。$set 操作会更新已有的元素,同时,$setOnInsert 操作会在插入一个新元素时,向其添加 createdAt 属性。
结论
本文探讨了 Mongoose 中更新嵌套数组时遇到的 $setOnInsert 未生效的问题。由于 Mongoose 的设计原因,$setOnInsert 并不会正确地更新新元素的属性值。为了解决这个问题,我们提供了两个解决方案:使用 $each 和 $position 或使用 findOneAndUpdate 方法。掌握这些技巧可以使您编写更加规范的 MongoDB 代码。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67026370d91dce0dc8474853