My aim is to search records of data userid 1
Below is my data
{ \"_id\" : 2,
\"name\" : \"test\",
\"data\" :[{\"_id\" : \"1\",\"file\" : \"nic\
You need the .aggregate() method in order to "filter" any array content for more than a singular match, and also the basic match is a lot simplier as MongoDB does not care that the data is within arrays, just as long as the specified path is correct:
db.collection.aggregate([
{ "$match": { "data.userid": 1 } },
{ "$project": {
"data": {
"$setDifference": [
{ "$map": {
"input": "$data",
"as": "el",
"in": {
"$cond": [
{ "$setIsSubset": [ [1], "$$el.userid" ] },
"$$el",
false
]
}
}},
[false]
]
}
}},
{ "$match": { "data.0": { "$exists": true } }}
])
With PHP this notates as follows:
$collection->aggregate(array(
array( '$match' => array( "data.userid" => 1 )),
array(
'$project' => array(
'data' => array(
'$setDifference' => array(
array(
'$map' => array(
'input' => '$data',
'as' => 'el',
'in' => array(
'$cond' => array(
array( '$setIsSubset' => array(array(1),'$$el.userid') ),
'$$el',
FALSE
)
)
)
),
array(FALSE)
)
)
)
),
array( '$match' => array( 'data.0' => array( '$exists' => TRUE ) ) )
))
The $map operator allows inspection of each element ofthe outer array and passed each element to the $cond ternary operation. This processes a $setIsSubset operation on the "inner" array to see if it in fact contains one of the values in the alternate set ( in this case [1]
) and where a true
evaluation is made then the element is returned or otherwise false
.
The point of $setDifference is to remove those false
values from the modified array and only return matched elements. And finally the $exists test looks to see that outer array actually has at least one element and is not empty as a result of the filtering.
The documents returned are the ones with the matching condition and only the array elements that also match the specified condition.
Of course the operators here require that you have at least MongoDB 2.6 as the server ( which is quite an old release now and an advised update at least ) but if you still have a lesser version then you need a traditional approach with $unwind and $group:
$collection->aggregate(array(
array( '$match' => array( "data.userid" => 1 )),
array( '$unwind' => '$data' ),
array( '$match' => array( 'data.userid' => 1 )),
array(
'$group' => array(
'_id' => '$_id',
'data' => array( '$push' => '$data' )
)
)
))