我试图通过文档的id
字段查找文档,然后仅在该字段的值为 false 时才更新该文档的另一个字段(isLocked
(。我只想更新isLockedField
.
MongoDB版本是4.2。
我的第一个方法是执行 2 个两个查询:
- 按 ID 查找文档。如果什么也没找到,就扔一个
NotFoundError
。 - 通过执行查询
{ id: 'the-id', isLocked: false }
来查找和更新文档,并返回新文档。如果此查询返回空响应,则表示文档已锁定,则抛出LockedError
(423(。
然后,我通过同时执行两个查询来优化该方法。在两个承诺解决后,如果对应,则抛出特定错误。
是否有另一种形式只需要对数据库进行一次查询并能够识别,如果返回空响应,为什么为空(未通过其 id 或因为它被锁定而找到(?
如果您不想将isLock更新为true,例如它不存在或与false
完全不同,则可以使用findOneAndUpdate
并指定聚合管道作为更新参数。
const result = db.collection('yourCollection').findOneAndUpdate(
{ id: 'this-id' },
[{ $set: { isLocked: { $cond: { if: { $eq: ['$isLocked', false] }, then: true, else: '$isLocked' } } } }]
)
if (result.value === null) return NotFoundError
if (result.value.isLocked) return LockedError
结果对象的value
字段包含更新操作之前的文档。
如果当字段不存在或包含任何其他数据类型时可以将isLocked
设置为 true,则可以删除条件和$set
周围的[]
,从而将其指定为正常更新而不是聚合管道(棘手,我知道(:
const result = db.collection('yourCollection').findOneAndUpdate(
{ id: 'this-id' },
{ $set: { isLocked: true } }
)
请参阅:http://mongodb.github.io/node-mongodb-native/3.5/api/Collection.html#findOneAndUpdate
如果只想修改isLocked
字段,可以使用.updateOne()
它返回以下内容:
res.n; // Number of documents matched
res.nModified; // Number of documents modified
因此,基本上无论当前值是多少,您都会尝试将isLocked
更新为true
。
然后,您将检查它是否已被修改。
基本上
const { n, nModified } = await Model.update({ id }, { $set: { isLocked: true } })
if (n === 0) {
throw new Error(‘NotFound’)
}
if (n > 0 && nModified === 0) { // or actually "if (nModified === 0)" because n should always be positive if it did not throw at the previous condition
throw new Error(‘Locked’)
}