How to match any field name in a query?

Hi everyone,

I have the following document schema:

{
   "_id": ObjectId("640c64740fb9216e3a1bd565"),
   "outer_field": {
       "some_field_1": ["apple", "orange"],
       "some_field_2": ["lemon", "orange"],
       "some_field_3": [],
       "some_field_4": ["apple"],
       "some_field_5": ["orange"],
       ...
    }  
}

I would like to $pull a speicfic value, let’s say apple, from all the arrays in the inner fields of outer_field but I’m unsure how to reference the inner fields since they’re unknown to me.

My initial thoughts are this query:

db.coll.update({}, {
    "$pull": {
      "outer_field.*": "apple"
    }
})

where * would match any/all fields and update all of them accordingly.

The expected result would be something like this:

{
   "_id": ObjectId("640c64740fb9216e3a1bd565"),
   "outer_field": {
       "some_field_1": ["orange"],
       "some_field_2": ["lemon", "orange"],
       "some_field_3": [],
       "some_field_4": [],
       "some_field_5": ["orange"],
       ...
    }  
}

Thank you.

Hello @loay_khateeb,

There is no straight way, but you can use an update with aggregation pipeline starting from MongoDB4.2,

  • $objectToArray to convert the object to an array of objects in key-value format
  • $map to iterate loop of above converted object
  • $filter to iterate loop of array values and check condition that value not equal to “apple”
  • $arrayToObject to convert back to an object from an array of object
db.coll.update({},
[
  {
    $set: {
      outer_field: {
        $arrayToObject: {
          $map: {
            input: { $objectToArray: "$outer_field" },
            in: {
              k: "$$this.k",
              v: {
                $filter: {
                  input: "$$this.v",
                  cond: {
                    $ne: ["$$this", "apple"]
                  }
                }
              }
            }
          }
        }
      }
    }
  }
])

Out of the question, I would suggest you improve your schema as below, which is called attribute pattern, and this will cover almost straight operations,

{
    "_id": ObjectId("640c64740fb9216e3a1bd565"),
    "outer_field": [
      {
        "field": "some_field_1",
        "value": ["apple", "orange"]
      },
      {
        "field": "some_field_2",
        "value": ["lemon", "orange"]
      },
      {
        "field": "some_field_3",
        "value": []
      },
      {
        "field": "some_field_4",
        "value": ["apple"]
      },
      {
        "field": "some_field_5",
        "value": ["orange"]
      }
    ]
  }

And your query would be:

db.coll.update({},
{
  $pull: {
    "outer_field.$[].value": "apple"
  }
})
1 Like

After some research, I’ve decided to use the attribute pattern.

Thank you for the reply, @turivishal.

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.