Giới thiệu
Toán tử $elemMatch được thiết kế cho **mảng chứa object** (array of objects) để match nhiều điều kiện trên **cùng một element**. Đối với mảng cấp 1 chứa giá trị đơn giản (string, number), bạn **không cần** $elemMatch - chỉ dùng truy vấn trực tiếp hoặc $in.
Mảng cấp 1 giá trị đơn giản: Dùng $in hoặc truy vấn trực tiếp
Ví dụ: Kỹ năng kỹ thuật (mảng string)
> db.mangCap1.insertOne({ "TenSinhVien": "Chris", "KyNang": ["MongoDB", "MySQL", "SQL Server"] });
{ "acknowledged" : true, "insertedId" : ObjectId("5ca2360f66324ffac2a7dc71") }
> db.mangCap1.insertOne({ "TenSinhVien": "Robert", "KyNang": ["C", "Java", "C++"] });
{ "acknowledged" : true, "insertedId" : ObjectId("5ca2362766324ffac2a7dc72") }
Tìm sinh viên có kỹ năng "MongoDB" - Cách đơn giản
> db.mangCap1.find({ KyNang: "MongoDB" }).pretty();
{ "_id" : ObjectId("5ca2360f66324ffac2a7dc71"), "TenSinhVien" : "Chris", "KyNang" : [ "MongoDB", "MySQL", "SQL Server" ] }
Tương đương với $in
> db.mangCap1.find({ KyNang: { $in: ["MongoDB"] } }).pretty();
Khi nào CẦN $elemMatch?
Chỉ khi mảng chứa **object** và bạn cần match **nhiều điều kiện trên cùng một element**:
Ví dụ: Mảng object - Cần $elemMatch
// Dữ liệu
{ "sanPham": [ { "ten": "Ao", "gia": 100 }, { "ten": "Quan", "gia": 200 } ] }
// SAI: Tìm sản phẩm tên "Ao" VÀ giá 200 (match cross-element)
db.collection.find({ "sanPham.ten": "Ao", "sanPham.gia": 200 });
// Trả về doc (vì CÓ element tên Ao VÀ CÓ element giá 200)
// ĐÚNG: Tìm element CÓ CẢ tên "Ao" VÀ giá 200
db.collection.find({ sanPham: { $elemMatch: { ten: "Ao", gia: 200 } } });
// Không trả về (không có element nào thỏa cả 2)
Tóm tắt quy tắc chọn
| Kiểu mảng | Truy vấn đơn giản | Cần $elemMatch? |
|---|---|---|
Giá trị đơn giản: ["a", "b", "c"] | { field: "a" } hoặc { field: { $in: ["a"] } } | ❌ Không |
Object: [{a:1,b:2}, {a:3,b:4}] | { "field.a": 1 } (match field đơn lẻ) | ❌ Không |
Object: [{a:1,b:2}, {a:3,b:4}] | Cần match a=1 **VÀ** b=2 trên cùng element | ✅ Có |
Lưu ý
- $elemMatch trên mảng giá trị đơn giản vẫn hoạt động nhưng **thừa thãi** và chậm hơn
- Truy vấn trực tiếp
{ tags: "value" }có thể dùng **Multikey Index - $elemMatch cũng dùng trong
$project(aggregation) để lọc element trong mảng