关于mongodb:猫鼬:原子FindOne-Or-Insert(),如果发现则不更新现有实例

Mongoose: atomic FindOne-Or-Insert(), do not update existing instance if found

在猫鼬中,我寻求以原子方式执行Model.FindOne-Or-Insert()的功能,与当前可用的Model.FindOneAndUpdate()类似的功能和签名,除非存在实例(即匹配filter),然后不使用提供的object更新但是返回原样找到的实例,如果不存在(即与filter不匹配),则插入object并返回新实例。

我无法找到一种使用Model.FindOneAndUpdate()的方法,即通过尝试尝试修改其options的差异并且不向object提供不希望在实例存在时不进行更新的字段来不对现有实例执行更新。 >

因此,我当前的非原子变通方法是Model.FindOne(),如果找不到,请执行Document.save()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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)
}

建议?谢谢


您可以在更新参数中使用$setOnInsert,使其仅适用于插入大小写;在文档已存在的情况下,更新变为无操作:

1
2
3
4
5
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中包含的字段上创建唯一索引,然后处理重复错误的可能性。有关原因的详细信息,请参见此帖子。