Du behöver .aggregate()
metod för att "filtrera" något arrayinnehåll för mer än en singular matchning, och även den grundläggande matchningen är mycket enklare eftersom MongoDB inte bryr sig om att data finns inom arrayer, bara så länge den angivna sökvägen är 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 ser detta följande ut:
$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
operatorn tillåter inspektion av varje element i den yttre arrayen och skickade varje element till
strong>$cond
ternär operation. Detta bearbetar en $setIsSubset
operation på den "inre" arrayen för att se om den faktiskt innehåller ett av värdena i den alternativa uppsättningen (i detta fall [1]
) och där en true
utvärdering görs sedan returneras elementet eller på annat sätt false
.
Poängen med $setDifference
är att ta bort dessa false
värden från den modifierade matrisen och returnerar endast matchade element. Och slutligen $exists
testet ser att den yttre arrayen faktiskt har minst ett element och inte är tom som ett resultat av filtreringen.
De dokument som returneras är de med det matchande villkoret och endast de arrayelement som också matchar det angivna villkoret.
Självklart kräver operatörerna här att du har minst MongoDB 2.6 som server (vilket är en ganska gammal version nu och en rekommenderad uppdatering åtminstone) men om du fortfarande har en mindre version behöver du ett traditionellt tillvägagångssätt med $unwind
och $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' )
)
)
))