在猫鼬中,我寻求以原子方式执行一种Model.FindOne-Or-Insert()
,与当前可用Model.FindOneAndUpdate()
类似的功能和签名的方式,除非存在实例(即匹配filter
),然后不要使用提供的object
更新,而是返回原样找到的实例,如果不存在(即与filter
不匹配),则插入object
并返回新实例。 / p>
我无法通过尝试Model.FindOneAndUpdate()
与options
的差异以及不向object
提供不想更新的字段来对现有实例执行更新的方法如果实例存在。
因此,我目前的非原子解决方法是Model.FindOne()
,如果找不到,请执行Document.save()
。
const Foo = DB.model('foo', FooSchema)
async function findOneAndUpdateFoo(jsonFoo, next) {
const filter = {
deletedAt: null
}
if (jsonFoo.dsAccountId) {
filter.dsAccountId = jsonFoo.dsAccountId
}
if (jsonIntegration.dsUserId) {
filter.dsUserId = jsonIntegration.dsUserId
}
if (jsonFoo.providerId) {
filter.providerId = jsonFoo.providerId
}
const fooDoc = {
name: jsonFoo.name,
dsAccountId: jsonFoo.dsAccountId,
dsUserId: jsonFoo.dsUserId,
providerId: jsonFoo.providerId,
providerName: jsonFoo.providerName,
// Most of these fields could be empty
accessToken: jsonFoo.accessToken,
refreshToken: jsonFoo.refreshToken,
scope: jsonFoo.scope,
tokenType: jsonFoo.tokenType,
expiresAt: jsonFoo.expiresAt
}
return await Foo.findOneAndUpdate(
filter, // find a document with that filter
fooDoc, // document to insert when nothing was found
{ upsert: true, new: true, runValidators: true } // options
)
.catch(next)
}
建议?谢谢
答案 0 :(得分:4)
您可以在更新参数中使用$setOnInsert
,使其仅适用于插入大小写;在文档已存在的情况下,更新变为无操作:
return await Foo.findOneAndUpdate(
filter, // find a document with that filter
{$setOnInsert: fooDoc}, // document to insert when nothing was found
{ upsert: true, new: true, runValidators: true }
)
请注意,您还应该在filter
中包含的字段上创建唯一索引,然后处理重复错误的可能性。有关详细原因,请参见this post。