Search code examples
mongodbmongodb-query

Remove multiple elements from deeply nested array with single update query


I have following type of documents:

[
 {
 "_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",
              
            }
          ]
        }
      }
    }
  }
]
}
]

I need to find update query that remove all documents that do not have "did" , "dst" and "den" fields , in the document nested array above this are the sub-objects with id:[2,3,5] , in the real collection I dont know the id's , is there option to remove all at once ?

My playground attempt , but unsuccessfull

The document after the update need to look like:

[
 {
 "_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"
            }
          ]
        }
      }
    }
  }
]
}
]

Solution

  • Is this what you want?:

    db.collection.update(
    {},
    [
      {
        $set: {
          "_a": {
            $map: {
              input: "$_a",
              as: "external",
              in: {
                $cond: [
                  {
                    $gt: [
                      "$$external._p",
                      0
                    ]
                  },
                  {
                    _p: {
                      s: {
                        a: {
                          t: {
                            $filter: {
                              input: "$$external._p.s.a.t",
                              as: "item",
                              cond: {
                                $and: [
                                  {
                                    $gt: [
                                      "$$item.did",
                                      0
                                    ]
                                  },
                                  {
                                    $gt: [
                                      "$$item.dst",
                                      0
                                    ]
                                  },
                                  {
                                    $gt: [
                                      "$$item.den",
                                      0
                                    ]
                                  }
                                ]
                              }
                            }
                          }
                        }
                      },
                      c: {
                        t: {
                          $filter: {
                            input: "$$external._p.s.c.t",
                            as: "item",
                            cond: {
                              $and: [
                                {
                                  $gt: [
                                    "$$item.did",
                                    0
                                  ]
                                },
                                {
                                  $gt: [
                                    "$$item.dst",
                                    0
                                  ]
                                },
                                {
                                  $gt: [
                                    "$$item.den",
                                    0
                                  ]
                                }
                              ]
                            }
                          }
                        }
                      }
                    }
                  },
                  "$$external"
                ]
              }
            }
          }
        }
      }
    ], 
    {multi:true})
    

    See how it works on the playground example