Query dynamic keyed subdocument field

Hi
I’m trying to query on a subdocument field and return only matching subdocuments. I’m not too worried about the structure of the returned data, array or not for example.

Data looks like this where items in groups can have any key:

Topdocument: {
    groups: {
        subdoc1: {
            name: 'my name'
        },
        subdocXyz: {
            name: 'my name'
        }
        ...
    }
}

Query so far that does not work, giving error: “FieldPath field names may not start with ‘$’”

db.getCollection('mycollection').aggregate([
    {
        $project: {
            dynamicKeys: { $objectToArray: "$groups" }
        }
    },
    {
        $match: {
            'dynamicKeys': {
                $elemMatch: {
                    "v.name": /my group name/
                }
            }
        }
    },
    {
        $project: {
            $filter: {
                input: "$dynamicKeys",
                as: "dk",
                cond: {
                    $eq: [ "$$dk.name", "my group name" ]
                }
            }
        }
    },
    {
        $limit: 3
    }
])
1 Like

You should implement your dynamic keyed sub-documents using the attribute pattern.

What you are doing in

is essential transforming your non-attribute-patterned sub-documents into an attribute-patterned sub-documents.

The attribute pattern will save you processing time doing this transformation, it will allow indexing of the dynamic keys and simplify your queries.

As for the error

the cause is that your last $project had not the correct syntax. You need a path name where you have $filter. Such as:

$project: {
            filtered_dynamic_keys : { $filter: {
                input: "$dynamicKeys",
                as: "dk",
                cond: {
                    $eq: [ "$dk.name", "my group name" ]
                }
            } }
        }
1 Like

Hi @steevej thanks for the answer! I’m not sure why but the $eq expression, I think 2 $'s are needed, eg:
"$$dk.name"
Also this needs to actually reference the values so needs to be:
"$$dk.v.name"