MongoDB - Performing an upsert on an array if arrayFilters are not satisfied

Viewed 567

I have the following document stored in mongo:

{
"_id" : ObjectId("5d1a08d2329a3c1374f176df"),
"associateID" : "1234567",
"associatePreferences" : [ 
    {
        "type" : "NOTIFICATION",
        "serviceCode" : "service-code",
        "eventCode" : "test-template",
        "preferences" : [ 
            "TEXT", 
            "EMAIL"
        ]
    }, 
    {
        "type" : "URGENT_NOTIFICATION",
        "serviceCode" : "service-code",
        "eventCode" : "test-template",
        "preferences" : [ 
            "TEXT"
        ]
    }
]
}

I am basically trying to query one of the elements of the associatePreferences array based off of its type, serviceCode, and eventCode and add a new value to the preferences array. However, if that combination of type, serviceCode, and eventCode is not present, I would like to add a new element to the associatePreferences array with those values. This is my current query:

db.user_communication_preferences.update(
   {'associateID':'testassociate'}, 
   {$addToSet:{'associatePreferences.$[element].preferences':"NEW_VALUE"}}, 
   {arrayFilters:[{'element.serviceCode':'service-code-not-present', 'element.eventCode':'event-code-not-present','element.type':'URGENT_NOTIFICATION'}]}
)

This query works if all of the arrayFilters are present in the an element of associatePreferences, but it does not add a new element if it is not present. What am I missing?

1 Answers

You can use aggregation pipeline to check the existence of the element, then append the element to associatePreferences array conditionally. Finally, using the aggregation result to update back your document.

db.user_communication_preferences.aggregate([
  {
    "$match": {
      "associateID": "testassociate"
    }
  },
  {
    "$addFields": {
      "filteredArray": {
        "$filter": {
          "input": "$associatePreferences",
          "as": "pref",
          "cond": {
            $and: [
              {
                $eq: [
                  "$$pref.type",
                  "URGENT_NOTIFICATION"
                ]
              },
              {
                $eq: [
                  "$$pref.eventCode",
                  "event-code-not-exists"
                ]
              },
              {
                $eq: [
                  "$$pref.serviceCode",
                  "service-code-not-exists"
                ]
              }
            ]
          }
        }
      }
    }
  },
  {
    $addFields: {
      "needAddElement": {
        $eq: [
          {
            "$size": "$filteredArray"
          },
          0
        ]
      }
    }
  },
  {
    "$addFields": {
      "associatePreferences": {
        "$concatArrays": [
          "$associatePreferences",
          {
            "$cond": {
              "if": {
                $eq: [
                  "$needAddElement",
                  true
                ]
              },
              "then": [
                {
                  "type": "URGENT_NOTIFICATION",
                  "serviceCode": "service-code-not-exists",
                  "eventCode": "event-code-not-exists",
                  "preferences": [
                    "TEXT"
                  ]
                }
              ],
              "else": []
            }
          }
        ]
      }
    }
  }
]).forEach(result){
    db.user_communication_preferences.update({
        _id : result._id
    }, {
        $set: {
            "associatePreferences" : result.associatePreferences
        }
    })
}
Related