You can use $strLenCP
within $expr
and some careful handling of processing through arrays:
db.collection.find({
"$expr": {
"$anyElementTrue": {
"$map": {
"input": {
"$reduce": {
"input": "$key.array.arrKey",
"initialValue": [],
"in": { "$concatArrays": [ "$$value", "$$this" ] }
}
},
"in": { "$gte": [ { "$strLenCP": "$$this" }, 5 ] }
}
}
}
})
If you have a MongoDB older than 3.6 you can use $where
instead:
db.collection.find({
"$where": function() {
return this.key.reduce((o,e) => o.concat(e.array.map(a => a.arrKey)), [])
.some(e => e.length >= 5);
}
})
Both follow the same principal of accessing the inner array elements by "concatenating" into a single array of strings, then testing those elements to see if they matched the length requirements.
The following is to deter incorrect responses
NOTE: Before anyone else jumps on here and says "Hey, can't you just do this:"
db.collection.find({
"$expr": { "$gte": [ { "$strLenCP": "$key.array.arrKey" }, 5 ] }
})
Then NO, you cannot, and the reason very simply is to look at what that aggregation expression notation actually does:
db.collection.aggregate([
{ "$project": {
"value": "$key.array.arrKey"
}}
])
Returns:
{ "_id" : "id", "value" : [ [ "value" ] ] }
So the returned value of "$key.array.arrKey"
is NOT the "string" of "value"
but is instead the nested array as shown above. Hence the reduce and array concatenation to a single array of strings, and then the map operation over those array elements to test each element.
That is why both the aggregation expression AND the JavaScript expression follow the same logic pattern. Since "$key.array.arrKey"
sees a completely different picture to what .find({ "key.array.arrKey": { "$exists: true } })
might do things.
Aggregation expressions and query operators work very differently.
Noting of course that looking for strings longer than 6
( or any length longer than the actual string ):
db.collection.find({
"$expr": { "$gte": [ { "$strLenCP": "$key.array.arrKey" }, 6 ] }
})
would return the supplied document in the question in error.
Note also that in this case the $strLenCP
is actually comparing the "stringified" notation of the array, including the brackets []
and spacing. Which is of course incorrect.