0

I would like mongodb to only return a matching item from an array. For some reason it returns the complete document and not just the item.

My data :

{
    "car_type": "fiat",
    "car_parts": [
        {"part_name": "door", "part_color": "blue"},
        {"part_name": "roof", "part_color": "purple"}
    ]
},
{
    "car_type": "ferrari",
    "car_parts": [
        {"part_name": "door", "part_color": "red"},
        {"part_name": "wheels", "part_color": "yellow"}
    ]
},

If I do

collection.find_one(filter={"car_type": "fiat", "car_parts": {"$elemMatch": {"part_color": "blue"}}})

I get the complete document :

{
    "car_type": "fiat",
    "car_parts": [
        {"part_name": "door", "part_color": "blue"},
        {"part_name": "roof", "part_color": "purple"}
    ]
}

What I would like instead is the matching item from the array

{"part_name": "door", "part_color": "blue"}
  

There is plenty documentation about matching an item from an array but none about getting only the matching item instead of getting the whole doc. I really don't want to get all of the array's content. I just need the matching item, that's all...

Thx

Doctor
  • 7,115
  • 4
  • 37
  • 55

1 Answers1

0

Solved it...

It's kind of a duplicate of this very old question Retrieve only the queried element in an object array in MongoDB collection

The best approch to get only the item(s) that match and not the full document is by using $filter which is in my opinion very badly registered by search engines as I never stumble upon it...

collection.aggregate([{"$match": {"car_type": "ferrari"}},
        {"$project": {
            "car_parts": {
                "$filter": {
                    "input": "$car_parts",
                    "as": "car_part",
                    "cond": {"$eq": ["$$car_part.part_color", "red"]}
                }
            }
        }}
        ])

Note that "$$" is normal.
The value of "as" can be anything but should preferably be the singular of what you are searching for and must then be used inside the "cond" expression.

This will return something like this :

[
  {
    "_id": ObjectId('61d80660961da1a184cb8c85'),
    "car_parts": [
      {"part_name": "door", "part_color": "red"}
    ]
  }
]

The outer array is useless but it's easy to get rid of it.
Also remember that agregations don't return a dict but a cursor.
The easiest way to print its content is by using list

print(str(list(req_result)))
Doctor
  • 7,115
  • 4
  • 37
  • 55