Potrzebujesz .aggregate()
metoda w celu "filtrowania" dowolnej zawartości tablicy pod kątem więcej niż pojedynczego dopasowania, a także podstawowe dopasowanie jest znacznie prostsze, ponieważ MongoDB nie dba o to, że dane znajdują się w tablicach, o ile podana ścieżka jest poprawna:
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 } }}
])
W PHP oznacza to następująco:
$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
Operator umożliwia inspekcję każdego elementu tablicy zewnętrznej i przekazuje każdy element do $cond
działanie trójskładnikowe. Przetwarza to $setIsSubset
operacja na tablicy "wewnętrznej", aby sprawdzić, czy faktycznie zawiera ona jedną z wartości w zestawie alternatywnym (w tym przypadku [1]
) i gdzie true
ocena jest wykonywana, a następnie element jest zwracany lub w przeciwnym razie false
.
Punkt $setDifference
jest usunięcie tych false
wartości ze zmodyfikowanej tablicy i zwracają tylko dopasowane elementy. I wreszcie $exists
test sprawdza, czy tablica zewnętrzna faktycznie zawiera co najmniej jeden element i nie jest pusta w wyniku filtrowania.
Zwracane są dokumenty z pasującym warunkiem i tylko te elementy tablicy, które również pasują do określonego warunku.
Oczywiście operatorzy tutaj wymagają, abyś miał co najmniej MongoDB 2.6 jako serwer (co jest teraz dość starym wydaniem i przynajmniej zalecaną aktualizacją), ale jeśli nadal masz słabszą wersję, potrzebujesz tradycyjnego podejścia z $unwind
i $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' )
)
)
))