Home > Mobile >  How to set the value of a field if it doesn't exist in a document in mongodb and keep it as it
How to set the value of a field if it doesn't exist in a document in mongodb and keep it as it

Time:10-01

So assume I have a document as shown below

{
    "_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"),
}

Now I already have a temp ID assigned to the doc and sometimes that field might expire and not exist inside the document. I wanted to know if I'm updating the document with a different receivedAt parameter or any other parameter and it does not have a tempId then only assign it a tempId else let the tempId be as it is.

What should be the query for this to get the updated docs as given by two examples?

Case 1: If tempId exists:

{
    "_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"),
}

Case 2: If there is no temp Id and it is generated as 13qeqrwrqwtqrfsdfweqr in above lines and document needs to be updated with the generated 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"),
}

Query would be something like this

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
            }
        }
    }
})

CodePudding user response:

Work with update with aggregation pipeline. Use $cond operator to check whether tempId is not equal ($ne) to undefined.

If true, remain existing value $tempId.

If false, assign value: "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

CodePudding user response:

I agree with @Yong Shun that using an aggregation pipeline to describe the transformation is the correct way to approach this. I offer an alternative syntax below just for general reference though both will satisfy the request as stated in the question perfectly fine.

Mainly just leaving an additional answer as I'm curious about why this workflow around tempId exists. What do they represent, why can the coexist with userIds, and why is the application generating a new one for each of these write operations even if one may already exist? One thing that comes to mind is that you can construct your filter predicates for your update to include references to tempId (perhaps to only have the application generate a new one if needed). But more importantly I suspect that the entire workflow with tempId should be simplified, but that would require more specific knowledge about the application to say for sure.

With respect to the alternative syntax, the tempId portion of the pipeline can be simplified to use the $ifNull operator:

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

Full demo playground here.

  • Related