Để lọc các phần tử trong mảng subdocument dựa trên việc **trường của phần tử có nằm trong một mảng giá trị cho trước không**, MongoDB cung cấp toán tử $setIsSubset trong Aggregation Pipeline. Toán tử này trả về true nếu tập hợp đầu tiên là tập con của tập hợp thứ hai.
1. Tạo bộ sưu tập và chèn dữ liệu
> db.demo407.insertOne({
Name: "Chris",
"details": [
{ id: 100 },
{ id: 110 },
{ id: 130 }
]
});
{ "acknowledged": true, "insertedId": ObjectId("5e70dffe15dc524f70227677") }
2. Xem dữ liệu
> db.demo407.find().pretty();
Kết quả:
{ "_id": ObjectId("..."), "Name": "Chris", "details": [ { "id": 100 }, { "id": 110 }, { "id": 130 } ] }
3. Lọc chỉ giữ phần tử có id IN [100, 130]
> db.demo407.aggregate([
{ $match: {} },
{
$project: {
"details": {
$filter: {
input: "$details",
as: "output",
cond: { $setIsSubset: [ ["$$output.id"], [100, 130] ] }
}
}
}
}
]);
4. Kết quả
{ "_id": ObjectId("..."), "details": [ { "id": 100 }, { "id": 130 } ] }
Giải thích:
$filter: Duyệt mảngdetails, giữ phần tử thỏacond.$$output.id: Trường id của phần tử hiện tại (bọc trong mảng["$$output.id"]để thành set).$setIsSubset: [ [A], [B] ]: Trả về true nếu A ⊆ B. Ở đây kiểm tra {id} ⊆ {100,130}.
Cách thay thế đơn giản hơn (MongoDB 3.6+): Dùng $in trong $filter:
cond: { $in: ["$$output.id", [100, 130]] }
Cách này dễ đọc hơn và hiệu suất tương đương.