Bạn cần có .aggregate()
để "lọc" bất kỳ nội dung mảng nào cho nhiều hơn một so khớp đơn lẻ và so khớp cơ bản cũng đơn giản hơn rất nhiều vì MongoDB không quan tâm rằng dữ liệu nằm trong các mảng, miễn là đường dẫn được chỉ định là chính xác:
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 } }}
])
Với PHP, ký hiệu này như sau:
$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
toán tử cho phép kiểm tra từng phần tử của mảng bên ngoài và chuyển từng phần tử đến $cond
hoạt động bậc ba. Quá trình này xử lý $setIsSubset
hoạt động trên mảng "bên trong" để xem liệu nó có thực sự chứa một trong các giá trị trong tập thay thế hay không (trong trường hợp này là [1]
) và trong đó true
đánh giá được thực hiện sau đó phần tử được trả về hoặc nếu không thì false
.
Điểm của $setDifference
là loại bỏ những false
đó giá trị từ mảng đã sửa đổi và chỉ trả về các phần tử phù hợp. Và cuối cùng thì $exists
kiểm tra để xem rằng mảng bên ngoài thực sự có ít nhất một phần tử và không trống do kết quả của quá trình lọc.
Các tài liệu được trả về là những tài liệu có điều kiện khớp và chỉ các phần tử mảng cũng khớp với điều kiện đã chỉ định.
Tất nhiên các nhà khai thác ở đây yêu cầu bạn phải có ít nhất MongoDB 2.6 làm máy chủ (đây là bản phát hành khá cũ hiện tại và ít nhất là bản cập nhật được khuyên dùng) nhưng nếu bạn vẫn có phiên bản thấp hơn thì bạn cần một cách tiếp cận truyền thống với $unwind
và $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' )
)
)
))