skip to Main Content

I want to use a pipeline to update a document by filtering on the keys of sub-documents in an object.

eg data:

{
  things: {
    a1: {},
    ...
    x1: {}
  }
}

Where "things" can contain variable keys/properties.
I know I can use an update pipeline like this, where "keepKeys" are the keys I want to keep in the "things" object:

[ 
  $set: {
    things: { 
      $arrayToObject: {
        $filter: {
          "input": {
            $objectToArray: "$$ROOT.things"
          },
          "as": "item",
          "cond": {
             "$in": [
               "$$item.k",
               keepKeys
             ]
          }
        }
     }
  } 
]

This works, but I’d rather filter out the things I don’t want as this is a much shorter list, eg where discardKeys are the keys I don’t want:

[ 
  $set: {
    things: { 
      $arrayToObject: {
        $filter: {
          "input": {
            $objectToArray: "$$ROOT.things"
          },
          "as": "item",
          "cond": {
             "$nin": [
               "$$item.k",
               discardKeys
             ]
          }
        }
     }
  } 
]

But $nin is not supported in pipeline $filter cond

2

Answers


  1. Chosen as BEST ANSWER

    This works, as per @Wernfrie Domscheit

    [ 
      $set: {
        things: { 
          $arrayToObject: {
            $filter: {
              "input": {
                $objectToArray: "$$ROOT.things"
              },
              "as": "item",
              "cond": {
                "$not": {
                  "$in": [
                    "$$item.k",
                    discardKeys
                  ]
                }
              }
            }
         }
      } 
    ]
    

  2. You can use $indexOfArray to check if the key is not present in discardKeys. Since $indexOfArray returns -1 when an element is not found.

    So if discardKeys = ["x1", "x2", "a3" ]:

    db.collection.aggregate([
      {
        $set: {
          things: {
            $arrayToObject: {
              $filter: {
                "input": {
                  $objectToArray: "$$ROOT.things"
                },
                "as": "item",
                "cond": {
                  $eq: [
                    { $indexOfArray: [["x1", "x2", "a3"], "$$item.k"] },
                    -1
                  ]
                }
              }
            }
          }
        }
      }
    ])
    

    Mongo Playground

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search