Du skal bruge .aggregate()
metode for at "filtrere" ethvert arrayindhold til mere end et enkelt match, og det grundlæggende match er også meget enklere, da MongoDB er ligeglad med, at dataene er inden for arrays, bare så længe den angivne sti er korrekt:
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 } }}
])
Med PHP lyder dette som følger:
$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 ) ) )
))
$map
operatøren tillader inspektion af hvert element i det ydre array og sendte hvert element til $cond
ternær drift. Dette behandler en $setIsSubset
operation på det "indre" array for at se, om det faktisk indeholder en af værdierne i det alternative sæt (i dette tilfælde [1]
) og hvor en true
evaluering foretages, derefter returneres elementet eller på anden måde false
.
Pointen med $setDifference
er at fjerne disse false
værdier fra det modificerede array og returnerer kun matchede elementer. Og endelig $exists
test ser ud for at se, at det ydre array faktisk har mindst ét element og ikke er tomt som følge af filtreringen.
De returnerede dokumenter er dem med den matchende betingelse og kun de array-elementer, der også matcher den angivne betingelse.
Operatørerne her kræver selvfølgelig, at du mindst har MongoDB 2.6 som server (hvilket er en ret gammel udgivelse nu og i det mindste en anbefalet opdatering), men hvis du stadig har en mindre version, har du brug for en traditionel tilgang med $unwind
og $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' )
)
)
))