What you are actually asking for is matching on the "count of the number of keys" within the array elements. You have different approaches to this depending on the available MongoDB version.
MongoDB 3.4.4 and upwards
You can use $objectToArray to coerce each element into an "array" itself, representing the "key/value" pairs of the elements:
db.collection.aggregate([
{ "$redact": {
"$cond": {
"if": {
"$anyElementTrue": {
"$map": {
"input": "$features",
"as": "f",
"in": {
"$lt": [
{ "$size": { "$objectToArray": "$$f" } },
2
]
}
}
}
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
You basically feed the condition with $redact which determines that for the results of $map where the $objectToArray is applied to each element and then tested for the $size, where any of the tested array elements returned true via $anyElementTrue.
All Other Versions
Anywhere else, looking somewhat more brief but actually not as performance effective is using $where to apply a JavaScript expression to test the array elements. Same principle though using Object.keys() and Array.some():
db.collection.find({
"$where": function() {
return this.features.some(f => Object.keys(f).length < 2 )
}
})
Same deal but since the JavaScript requires interpretation and evaluation against every document, it actually runs quite a bit slower that the aggregation expression given.
Both return the same document, which is the one which has an element with "less than two keys" in the inner object, just as asked:
/* 1 */
{
"productId" : 123.0,
"features" : [
{
"a" : true
},
{
"a" : true,
"b" : true
}
]
}