การค้นหาเอกสารด้วย Tags (Array Field) ใน MongoDB
ใช้ ออเปอเรเตอร์ $elemMatch หรือ Query โดยตรงบน Array Field เพื่อค้นหาเอกสารที่มี Tag ที่ต้องการ
ตัวอย่างการสร้างคอลเลกชันและเพิ่มข้อมูล
> db.getDocumentsByTagsDemo.insertOne({"Tags":["Tag-1", "Tag-2", "Tag-3"]});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9eb4d5d628fa4220163b79") }
> db.getDocumentsByTagsDemo.insertOne({"Tags":["Tag-2", "Tag-4", "Tag-5"]});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9eb4d5d628fa4220163b7a") }
> db.getDocumentsByTagsDemo.insertOne({"Tags":["Tag-6", "Tag-4", "Tag-3"]});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9eb4d6d628fa4220163b7b") }
แสดงข้อมูลทั้งหมด
> db.getDocumentsByTagsDemo.find().pretty();
ผลลัพธ์:
{ "_id" : ObjectId("5c9eb4d5d628fa4220163b79"), "Tags" : [ "Tag-1", "Tag-2", "Tag-3" ] }
{ "_id" : ObjectId("5c9eb4d5d628fa4220163b7a"), "Tags" : [ "Tag-2", "Tag-4", "Tag-5" ] }
{ "_id" : ObjectId("5c9eb4d6d628fa4220163b7b"), "Tags" : [ "Tag-6", "Tag-4", "Tag-3" ] }
วิธีที่ 1: ใช้ $elemMatch (สำหรับ Array of Objects หรือเงื่อนไขซับซ้อน)
> db.getDocumentsByTagsDemo.find({Tags: { $elemMatch: { $eq: "Tag-2" } }}).pretty();
ผลลัพธ์ (มี Tag-2):
{ "_id" : ObjectId("5c9eb4d5d628fa4220163b79"), "Tags" : [ "Tag-1", "Tag-2", "Tag-3" ] }
{ "_id" : ObjectId("5c9eb4d5d628fa4220163b7a"), "Tags" : [ "Tag-2", "Tag-4", "Tag-5" ] }
วิธีที่ 2: Query โดยตรงบน Array (Simple Equality) - แนะนำสำหรับ Simple Tags
> db.getDocumentsByTagsDemo.find({Tags: "Tag-5"}).pretty();
ผลลัพธ์ (มี Tag-5):
{ "_id" : ObjectId("5c9eb4d5d628fa4220163b7a"), "Tags" : [ "Tag-2", "Tag-4", "Tag-5" ] }
ความแตกต่าง $elemMatch vs Direct Query
| คุณสมบัติ | Direct Query {Tags: "Tag-2"} | $elemMatch {$elemMatch: {$eq: "Tag-2"}} |
|---|---|---|
| Simple Array (Strings) | ✅ ทำงานได้ดี เร็วกว่า | ✅ ทำงานได้ แต่ Overhead มากกว่า |
| Array of Objects | ❌ ไม่ได้ (Match ทั้ง Object) | ✅ จำเป็นต้องใช้ |
| Multiple Conditions on Same Element | ❌ Match แยก Element ได้ | ✅ Match ใน Element เดียวกัน |
| Performance | ดีกว่า (Simple Index Scan) | ช้ากว่า (Complex Matching) |
ตัวอย่าง Array of Objects (ต้องใช้ $elemMatch)
> db.products.insertOne({
name: "Laptop",
specs: [
{ name: "RAM", value: "16GB" },
{ name: "CPU", value: "i7" }
]
});
> db.products.insertOne({
name: "Phone",
specs: [
{ name: "RAM", value: "8GB" },
{ name: "CPU", value: "Snapdragon" }
]
});
// ❌ ผิด: จะ match ทั้ง RAM=16GB และ CPU=i7 ใน Document เดียวกัน (ไม่มี)
db.products.find({ "specs.name": "RAM", "specs.value": "8GB" });
// ✅ ถูก: ใช้ $elemMatch - match ใน Element เดียวกัน
db.products.find({
specs: { $elemMatch: { name: "RAM", value: "8GB" } }
});
Query Tags แบบหลายเงื่อนไข
// มี Tag-2 AND Tag-3 (ทั้งคู่)
db.getDocumentsByTagsDemo.find({ Tags: { $all: ["Tag-2", "Tag-3"] } });
// มี Tag-2 OR Tag-5 (อย่างน้อย 1 ตัว)
db.getDocumentsByTagsDemo.find({ Tags: { $in: ["Tag-2", "Tag-5"] } });
// มี Tag-2 แต่ไม่มี Tag-4
db.getDocumentsByTagsDemo.find({ Tags: "Tag-2", Tags: { $ne: "Tag-4" } });
// หรือ
db.getDocumentsByTagsDemo.find({
$and: [ { Tags: "Tag-2" }, { Tags: { $nin: ["Tag-4"] } } ]
});
Index สำหรับ Tags Array
// Single Field Index บน Array -> Multikey Index อัตโนมัติ
db.getDocumentsByTagsDemo.createIndex({ "Tags": 1 });
// Compound Index
db.getDocumentsByTagsDemo.createIndex({ "Tags": 1, "createdAt": -1 });
Aggregation สำหรับ Tag Analytics
// นับจำนวนเอกสารต่อ Tag
db.getDocumentsByTagsDemo.aggregate([
{ $unwind: "$Tags" },
{ $group: { _id: "$Tags", count: { $sum: 1 } } },
{ $sort: { count: -1 } }
]);
// Top 5 Tags
db.getDocumentsByTagsDemo.aggregate([
{ $unwind: "$Tags" },
{ $group: { _id: "$Tags", count: { $sum: 1 } } },
{ $sort: { count: -1 } },
{ $limit: 5 }
]);
สรุปคำแนะนำ
- Simple String Tags: ใช้ Direct Query
{ tags: "value" }เร็วที่สุด - Array of Objects: ต้องใช้
$elemMatch - Multiple Tags (AND): ใช้
$all - Multiple Tags (OR): ใช้
$in - Index: สร้าง Index บน Tags Field (Multikey Index อัตโนมัติ)