mongoose MongoDB -如何设置字段的值,如果它不存在,并保持字段,如果它已经在文档中呈现

x6492ojm  于 2023-03-30  发布在  Go
关注(0)|答案(2)|浏览(213)

假设我有一个如下所示的文档:

{
    "_id" : ObjectId("6336d94e0330f5d48e44fb0f"),
    "systemId" : "5124301",
    "userId" : "9876543210",
    "tempId" : "123456da87sdafasdf",
    "updatedAt" : ISODate("2022-09-30T12:01:11.714+0000"),
    "receivedAt" : ISODate("2022-04-10T23:15:08.145+0000"),
}

现在我已经为文档分配了一个tempId,有时该字段可能会过期,并且不存在于文档中。我想知道如果我正在使用不同的receivedAt参数或任何其他参数更新文档,并且它没有tempId,则只为其分配tempId,否则让tempId保持原样。
如两个示例所示,要获得更新的文档,应该查询什么?
情况1:如果tempId存在:

{
    "_id" : ObjectId("6336d94e0330f5d48e44fb0f"),
    "systemId" : "5124301",
    "userId" : "1234567890",
    "tempId" : "123456da87sdafasdf",
    "updatedAt" : ISODate("2022-09-30T12:01:11.714+0000"),
    "receivedAt" : ISODate("2022-04-10T23:15:08.145+0000"),
}

情况2:如果没有tempId,并且在上面的行中生成为“13qeqrwrqwtqrfsdfweqr”,则需要使用生成的tempId更新文档。

{
    "_id" : ObjectId("6336d94e0330f5d48e44fb0f"),
    "systemId" : "5124301",
    "userId" : "1234567890",
    "tempId" : "13qeqrwrqwtqrfsdfweqr",
    "updatedAt" : ISODate("2022-09-30T12:01:11.714+0000"),
    "receivedAt" : ISODate("2022-04-10T23:15:08.145+0000"),
}

查询将类似于以下内容:

findOneAndUpdate({
    systemId: "5124301"
},
{
    {
        $set: {
            userId: "1234567890",
            receivedAt : ISODate("2022-04-10T23:15:08.145+0000"),
            tempId: {
                      $exists: then leave it as is, else update it with 13qeqrwrqwtqrfsdfweqr
            }
        }
    }
})
kjthegm6

kjthegm61#

使用聚合管道更新。使用$cond运算符检查tempId是否不等于($neundefined
如果为true,则保留现有值$tempId
如果为false,则赋值:"13qeqrwrqwtqrfsdfweqr" .

findOneAndUpdate({
  systemId: "5124301"
},
[
  {
    $set: {
      userId: "1234567890",
      receivedAt: ISODate("2022-04-10T23:15:08.145Z"),
      tempId: {
        $cond: {
          if: {
            $ne: [
              "$tempId",
              undefined
            ]
          },
          then: "$tempId",
          else: "13qeqrwrqwtqrfsdfweqr"
        }
      }
    }
  }
])

Demo @ Mongo Playground

4c8rllxm

4c8rllxm2#

我同意@Yong Shun的观点,使用聚合管道来描述转换是解决这个问题的正确方法。我在下面提供了一个替代语法,只是作为一般参考,尽管两者都能很好地满足问题中的要求。
主要是留下一个额外的答案,因为我很好奇 * 为什么 * 这个围绕tempId的工作流程存在。它们代表什么,为什么可以与userId共存,以及为什么应用程序为这些写操作中的每一个生成新的写操作,即使一个写操作可能已经存在?有一件事需要注意,您可以为更新构建过滤 predicate ,以包含对tempId的引用(也许只让应用程序在需要的时候生成一个新的)。但更重要的是,我怀疑tempId的整个工作流程应该被简化,但这需要更具体的应用程序知识才能确定。
关于替代语法,流水线的tempId部分可以简化为使用$ifNull运算符:

tempId: { $ifNull: [ "$tempId", "13qeqrwrqwtqrfsdfweqr" ]

Full demo playground here .

相关问题