skip to Main Content

I have a problem with querying with MongoDB, here’s the data structure in MongoDB:

{
  "_id": "aaaaa",
  "groups": [
    {
      "name": "group0",
      "props": {
          "unknown1": "value1",
          "unknown2": "value2",
          "unknown3": "value3"
      }
    },
    {
      "name": "group1",
      "props": {
          "unknown4": "value4",
          "unknown5": "value5",
          "unknown6": "value6"
      }
    }
  ]
}

I want to query documents whose nested fields have specific value but the key is unknown , like : groups[X].props.unknownX.valueX = valueA.

I’v tried using aggregate query below :

db.collection.aggregate([
  {
    $project: {
      "props": "$groups.props"
    }
  },
  {
    $unwind: "$props"
  },
  {
    $project: {
      "result": {
        $objectToArray: "$props"
      }
    }
  },
  {
    $match: {
      $and: [
        {
          "result.k": "unknown2",
          "result.v": "value1"
        }
      ]
    }
  },
  {
    "$project": {
      result: {
        "$arrayToObject": "$result"
      }
    }
  }
])

A sandBox: https://mongoplayground.net/p/71TYThQnxTP

The result is :

[
  {
    "_id": "aaaaa",
    "result": {
      "unknown1": "value1",
      "unknown2": "value2",
      "unknown3": "value3"
    }
  }
]

But I expect it as :

[]

It should not be a array because I used $and operation by querying condition props.unknown2 = value1. But it seems return props.unknown2 exists and props.unknownX.value1 exists, is there anything wrong I make ?

Can anyone can help ? I will be grateful. Thank you!

2

Answers


  1. Your current query with the $match stage criteria only shows that the key and value exist. However it will not guarantee that both key and value must be within the same object (key-value pair).

    You should work with the $filter operator to filter the element in the array by key and value. Next, compare the filtered array by not equal to empty array [] to filter the (root document).

      {
        $match: {
          $expr: {
            $ne: [
              {
                $filter: {
                  input: "$result",
                  cond: {
                    $and: [
                      {
                        $eq: [
                          "$$this.k",
                          "unknown2"
                        ]
                      },
                      {
                        $eq: [
                          "$$this.v",
                          "value1"
                        ]
                      }
                    ]
                  }
                }
              },
              []
            ]
          }
        }
      }
    

    Demo 1 @ Mongo Playground

    The similar result can be achieved with the shortest query is constructing your search criteria like:

    db.collection.aggregate([
      {
        $match: {
          "groups.props.{key}": "{value}"
        }
      }
    ])
    

    So replacing the {key} and {value} to become:

    db.collection.aggregate([
      {
        $match: {
          "groups.props.unknown2": "value1"
        }
      }
    ])
    

    Demo 2 @ Mongo Playground

    Login or Signup to reply.
  2. You haven’t checked that both criteria are satisfied by a single element of the array. This is exactly what $elemMatch is for:

    {
        $match: {
          result: {
            $elemMatch: {
              "k": "unknown2",
              "v": "value1"
            }
          }
        }
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search