1

I have those kind of documents:

{
  "_id": "accountId 1",
  "codes": [
    {
      "key": "advantageCode 1",
      "dateBegin": "01/02/2012",
      "dateEnd": "01/02/2013"
    },
    {
      "key": "advantageCode 2",
      "dateBegin": "01/02/2012",
      "dateEnd": "01/02/2013"
    }
  ]
}

I would like to add a code in codes if it doesn't exist. I have tried this:

bulkWrite([{updateOne: {
            filter: { _id: commands[0].accountId },
            update: {$addToSet: {codes: {key: commands[0].advantageCode, dateBegin: commands[0].dateBegin, dateEnd: commands[0].dateEnd}}},
            upsert: true
}}])

My problem is that the object is always added into the set, even if the key property already exists. It is normal (because it is another reference), but I would like to know how to rebase the $addToSet to the key of the objects.

I need the request to be a bulkwrite, because i gather many different requests.

1 Answer 1

1

Using update/aggregation ( since 4.2+) you can do something even better:

 db.collection.update({
  "_id": "accountId 1"
 },
 [
 {
  $set: {
  codes: {
    $cond: [
      {
        $in: [
          "advantageCode 2",
          "$codes.key"
        ]
      },
      {
        $map: {
          input: "$codes",
          in: {
            $mergeObjects: [
              "$$this",
              {
                $cond: [
                  {
                    $eq: [
                      "$$this.key",
                      "advantageCode 2"
                    ]
                  },
                  {
                    "dateBegin": "01/02/2020",
                    "dateEnd": "01/02/2021"
                  },
                  {}
                ]
              }
            ]
          }
        }
      },
      {
        $concatArrays: [
          "$codes",
          [
            {
              "key": "advantageCode 2",
              "dateBegin": "01/02/2022",
              "dateEnd": "01/02/2023"
            }
          ]
        ]
      }
    ]
  }
 }
 }
])

Explained:

Update dateBegin and dateEnd for codes.key that matches , or if there is no match add the new codes object to the set.

Playground

Afcourse , if you only want to $addToSet if key is missing then you can do:

Playground2

The bulkWrite operation will look something like this:

bulkWrite([{updateOne: {
 filter: { _id: commands[0].accountId },
 update: [{ $set: { codes: { $cond: [ { $in: [commands[0].advantageCode,"$codes.key"]},{ $map: { input: "$codes",in: { $mergeObjects: [ "$$this", {}]}}},{$concatArrays: ["$codes",[{
        "key": commands[0].advantageCode , 
        "dateBegin": commands[0].dateBegin,
        "dateEnd": commands[0].dateEnd
          }
          ]
        ]
      }
    ]
   }
  }
 }
 ]
 }}])

If you need to upsert document in case accountId is not found here is the option:

 db.collection.update({
 "_id": "accountId 2"
 },
 [
 {
  $set: {
  codes: {
    "$cond": [
      {
        $ne: [
          {
            $type: "$codes"
          },
          "missing"
        ]
      },
      {
        $cond: [
          {
            $in: [
              "advantageCode 3",
              "$codes.key"
            ]
          },
          {
            $map: {
              input: "$codes",
              in: {
                $mergeObjects: [
                  "$$this",
                  {}
                ]
              }
            }
          },
          {
            $concatArrays: [
              "$codes",
              [
                {
                  "key": "advantageCode 3",
                  "dateBegin": "01/02/2022",
                  "dateEnd": "01/02/2023"
                }
              ]
            ]
          }
        ]
      },
      {
        "key": "advantageCode 3",
        "dateBegin": "01/02/2022",
        "dateEnd": "01/02/2023"
      }
    ]
    }
   }
  }
  ],
  {
   upsert: true
 })

Explained:

  1. In case accountId is not found insert new document.
  2. In case codes.key is not found insert new object with the new key to the codes array.

Playground3

Sign up to request clarification or add additional context in comments.

7 Comments

in my case, I have to bulkwrite because I regroup many request. How can I adapt this code into thi one: bulkWrite([{updateOne: { filter: { accountId: "accountId 1"}, update: {$addToSet: {codes: {code: commands[0].advantageCode, dateBegin: commands[0].dateBegin, dateEnd: commands[0].dateEnd}}}, upsert: true }}])
@Janus updated my answer with bulkWrite example as well
thanks a lot :) When I try to add the property "upsert: true" to the request, I have this error: "MongoBulkWriteError: $in requires an array as a second argument, found: missing" Do I miss something ?
Yes, because the document needs to be inserted if doesn't exists. If I update without upsert option, it doesn't create the document of it doesn't exists :/
In the end, I can handle this with $addToSet and $pull, as mongo will check the equality of the values of the properties of each objects. But thanks a lot for your help :)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.