Anda memerlukan .aggregate()
metode untuk "memfilter" konten array apa pun untuk lebih dari satu kecocokan tunggal, dan juga kecocokan dasar jauh lebih sederhana karena MongoDB tidak peduli bahwa data ada di dalam array, selama jalur yang ditentukan benar:
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 } }}
])
Dengan PHP notasi ini sebagai berikut:
$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 mengizinkan pemeriksaan setiap elemen larik luar dan meneruskan setiap elemen ke $cond
$setIsSubset
operasi pada larik "dalam" untuk melihat apakah itu sebenarnya berisi salah satu nilai dalam set alternatif ( dalam hal ini [1]
) dan di mana true
evaluasi dilakukan kemudian elemen dikembalikan atau sebaliknya false
.
Inti dari $setDifference
adalah untuk menghapus false
nilai dari array yang dimodifikasi dan hanya mengembalikan elemen yang cocok. Dan akhirnya $exists
test terlihat untuk melihat bahwa array luar sebenarnya memiliki setidaknya satu elemen dan tidak kosong sebagai hasil dari pemfilteran.
Dokumen yang dikembalikan adalah dokumen dengan kondisi yang cocok dan hanya elemen array yang juga cocok dengan kondisi yang ditentukan.
Tentu saja operator di sini mengharuskan Anda memiliki setidaknya MongoDB 2.6 sebagai server (yang merupakan rilis yang cukup lama sekarang dan setidaknya pembaruan yang disarankan) tetapi jika Anda masih memiliki versi yang lebih rendah maka Anda memerlukan pendekatan tradisional dengan $unwind
dan $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' )
)
)
))