0

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 )

1 Answer 1

2

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.

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

4 Comments

This is a very nice solution!
@nimrodserok Thanks! I tried for way too long to implement a "$function" that would field-name-agnosticly recursively descend and filter t when it was found, but I failed. It seems many static functions, e.g. Object.entries(), don't work more than once (?) in a MongoDB "$function". After trying several javascript options and failing, I just gave up.
Indeed very nice solution , I have tested unfortunately another small issue appear , when there is no s (missed to add in the example) fields under _p object it remove any other objects and leave s: null , accepting this answer since it gives some ideas , but will open new question including objects _p with no nested object s since this is the real case I have ...

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.