0

I have following document on which the update needs to be done.


    {
        "_id": "Colorcode_1",
        "Combination": [
            {
                "color": [
                    {
                        "mixture": [
                            "Red",
                            "Green"
                        ]
                    }
                ],
                "code": "Maroon"
            },
            {
                "color": [
                    {
                        "mixture": [
                            "Yellow",
                            "Green"
                        ]
                    }
                ],
                "code": "Light Green"
            }
        ]
    }

Now what I need to do is to update the document by adding the value "Blue" in the "mixture" field where "code" is "Maroon". Something like this. This needs to be done using $addToSet


    {
        "_id": "Colorcode_1",
        "Combination": [
            {
                "color": [
                    {
                        "mixture": [
                            "Red",
                            "Green",
                            "Blue"
                        ]
                    }
                ],
                "code": "Maroon"
            },
            {
                "color": [
                    {
                        "mixture": [
                            "Yellow",
                            "Green"
                        ]
                    }
                ],
                "code": "Light Green"
            }
        ]
    }

Any help regarding this would be highly helpful.

2
  • Just wondering ... Why is "color" an array? Commented May 5, 2022 at 14:39
  • Above document is just then reference to the problem I am facing. So it is self made example. @rickhg12hs Commented May 5, 2022 at 15:08

2 Answers 2

3

Here is option with arrayFilters:

db.collection.update({
   "Combination.code": "Maroon"
  },
  {
   "$addToSet": {
    "Combination.$[x].color.$[y].mixture": "Blue"
   }
 },
 {
  arrayFilters: [
  {
    "x.code": "Maroon"
  },
  {
   "y.mixture": {
    $exists: true
  }
}
 ]
})

Explained:

  1. Filter all documents having code:Marron , good to have index on this field if collection is big
  2. Use arrayFilter x.code to add the array element to mixture if mixture exists ( identified by y arrayFilter)

playground

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

5 Comments

What happens if the "color" array has objects without the the "mixture" field?
Ah you are right , added one more $filter y to identify if mixture $exists
Wow! This is excellent! I'll leave my answer as a lesson to myself and encouragement for all to learn more.
Yours also interesting and working , but abit complex ...
Would be interesting to "look under the hood" and see the real differences between the two updates. E.g., is the server "compiling/optimizing" both updates to the same thing?
2

I found this update difficult because of the data model, and I'm hoping you'll get a better/simpler answer.

Anyway, here's one way you could do it. I would test this on more/different data to insure it's correct.

db.collection.update({
  "_id": "Colorcode_1",
  "Combination.code": "Maroon"
},
[
  {
    "$set": {
      "Combination": {
        "$map": {
          "input": "$Combination",
          "as": "elem",
          "in": {
            "$cond": [
              { "$eq": [ "$$elem.code", "Maroon" ] },
              {
                "$mergeObjects": [
                  "$$elem",
                  {
                    "color": {
                      "$map": {
                        "input": "$$elem.color",
                        "as": "colorElem",
                        "in": {
                          "$cond": [
                            {
                              "$reduce": {
                                "input": { "$objectToArray": "$$colorElem" },
                                "initialValue": false,
                                "in": {
                                  "$or": [
                                    "$$value",
                                    { "$eq": [ "$$this.k", "mixture" ] }
                                  ]
                                }
                              }
                            },
                            {
                              "mixture": {
                                "$setUnion": [ "$$colorElem.mixture", [ "Blue" ] ]
                              }
                            },
                            "$$colorElem"
                          ]
                        }
                      }
                    }
                  }
                ]
              },
              "$$elem"
            ]
          }
        }
      }
    }
  }
])

Try it on mongoplayground.net.

1 Comment

looks a lot going inside the query, but works

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.