Home > Mobile >  Remove multiple objects from deeply nested array 2
Remove multiple objects from deeply nested array 2

Time:11-04

I need to remove some inconsistent objects not having did,dst and den from deeply nested array , please, advice if this can be done with single update query for all documents in the collection ?

This is example of my original document:

[
 {
  "_id": ObjectId("5c05984246a0201286d4b57a"),
 f: "x",
 "_a": [
 {
   "_onlineStore": {}
 },
 {
 "_p": {
  "s": {
    "a": {
      "t": [
        {
          id: 1,
          "dateP": "20200-09-20",
          did: "x",
          dst: "y",
          den: "z"
        },
        {
          id: 2,
          "dateP": "20200-09-20"
        }
      ]
    },
    "c": {
      "t": [
        {
          id: 3,
          "dateP": "20300-09-22",
          
        },
        {
          id: 4,
          "dateP": "20300-09-23",
          did: "x",
          dst: "y",
          den: "z"
        },
        {
          id: 5,
          "dateP": "20300-09-23",
          
        }
      ]
    }
  }
 }
}
]
}
]

After the update , the document need to look as follow:

 [
 {
  "_id": ObjectId("5c05984246a0201286d4b57a"),
  f: "x",
  "_a": [
  {
  "_onlineStore": {}
 },
 {
 "_p": {
  "s": {
    "a": {
      "t": [
        {
          id: 1,
          "dateP": "20200-09-20",
          did: "x",
          dst: "y",
          den: "z"
        }
      ]
    },
    "c": {
      "t": [
        {
          id: 4,
          "dateP": "20300-09-23",
          did: "x",
          dst: "y",
          den: "z"
        }
      ]
    }
  }
 }
}
]
}
]

Please, note a.t , c.t and d.t are all possible objects inside s object , but they are not compulsory in all documents so in some documents they can be missing , in other documents there can be only a.t and c.t ,but not d.t ...

@nimrod serok helped with a partial solution here:

Remove multiple elements from deep nested array with single update query

, but there is a small drawback , missing a,c, or d objects in original document do not need to appear in the resulting document as null since they do not exist and not expected:

playground

( d.t:null and c.t:null shall not appear after the update )

CodePudding user response:

Here's one way you could do it where the field name after _p.s could be anything. It feels a bit fragile though since all the other field names and depths need to be constant.

db.collection.update({},
[
  {
    "$set": {
      "_a": {
        "$map": {
          "input": "$_a",
          "as": "elem",
          "in": {
            "$cond": [
              {"$eq": [{"$type": "$$elem._p"}, "missing"]},
              "$$elem",
              {
                "_p": {
                  "s": {
                    "$arrayToObject": {
                      "$map": {
                        "input": {"$objectToArray": "$$elem._p.s"},
                        "as": "anyKey",
                        "in": {
                          "k": "$$anyKey.k",
                          "v": {
                            "t": {
                              "$filter": {
                                "input": "$$anyKey.v.t",
                                "as": "t",
                                "cond": {
                                  "$setIsSubset": [
                                    ["did", "dst", "den"],
                                    {
                                      "$map": {
                                        "input": {"$objectToArray": "$$t"},
                                        "in": "$$this.k"
                                      }
                                    }
                                  ]
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            ]
          }
        }
      }
    }
  }
],
{"multi": true}
)

Try it on mongoplayground.net.

  • Related