Je hebt de .aggregate()
nodig
methode om elke array-inhoud te "filteren" voor meer dan een enkelvoudige overeenkomst, en ook de basisovereenkomst is een stuk eenvoudiger omdat MongoDB er niet om geeft dat de gegevens zich in arrays bevinden, zolang het opgegeven pad maar correct is:
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 } }}
])
Met PHP wordt dit als volgt genoteerd:
$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 ) ) )
))
De $map
operator staat inspectie van elk element van de buitenste array toe en geeft elk element door aan de $cond
ternaire operatie. Dit verwerkt een $setIsSubset
bewerking op de "innerlijke" array om te zien of deze inderdaad een van de waarden in de alternatieve set bevat (in dit geval [1]
) en waar een true
evaluatie is gemaakt, dan wordt het element geretourneerd of anders false
.
Het punt van $setDifference
is om die false
. te verwijderen waarden uit de gewijzigde array en retourneert alleen overeenkomende elementen. En tot slot de $exists
test kijkt of de buitenste array daadwerkelijk ten minste één element bevat en niet leeg is als gevolg van de filtering.
De geretourneerde documenten zijn die met de overeenkomende voorwaarde en alleen de array-elementen die ook overeenkomen met de opgegeven voorwaarde.
Natuurlijk vereisen de operators hier dat je ten minste MongoDB 2.6 als server hebt (wat nu een vrij oude release is en op zijn minst een geadviseerde update), maar als je nog steeds een mindere versie hebt, dan heb je een traditionele aanpak nodig met $unwind
en $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' )
)
)
))