การค้นหาเอกสารที่ array field มี element เป็น substring ของคำที่กำหนด (เช่น array มี "john" และ "jace" ซึ่งเป็น substring ของ "john") ต้องใช้ aggregate pipeline พร้อม $expr, $map, $indexOfBytes
สร้างคอลเลกชันและข้อมูลตัวอย่าง
> db.demo90.insertOne({ "words": ["john", "jace"] });
{ "acknowledged" : true, "insertedId" : ObjectId("5e2c1ada79799acab037af56") }
> db.demo90.insertOne({ "words": ["sam", "adam"] });
{ "acknowledged" : true, "insertedId" : ObjectId("5e2c1adb79799acab037af57") }
แสดงข้อมูล
> db.demo90.find();
ผลลัพธ์:
{ "_id" : ObjectId("5e2c1ada79799acab037af56"), "words" : [ "john", "jace" ] }
{ "_id" : ObjectId("5e2c1adb79799acab037af57"), "words" : [ "sam", "adam" ] }
Query ค้นหา Array ที่มี Element เป็น Substring ของ "john"
> db.demo90.aggregate([
{ $match: {
$expr: {
$anyElementTrue: {
$map: {
input: "$words",
as: "j",
in: {
$ne: [
-1,
{ $indexOfBytes: [ "john", "$$j" ] }
]
}
}
}
}
}}
]);
คำอธิบายขั้นตอน:
$map: วนลูปทุก element ใน array words (ตัวแปร $$j)$indexOfBytes: ["john", "$$j"]: หาตำแหน่งของ $$j ใน string "john" (คืน -1 ถ้าไม่พบ)$ne: [-1, ...]: ตรวจสอบว่าไม่เท่ากับ -1 (คือพบ substring)$anyElementTrue: true ถ้ามี element ใด element หนึ่ง true$expr+$match: ใช้ expression ในการ filter
ผลลัพธ์
{ "_id" : ObjectId("5e2c1ada79799acab037af56"), "words" : [ "john", "jace" ] }
เอกสารแรก: "john" อยู่ใน "john" (index 0), "jace" อยู่ใน "john" (index 0 - ตรงตัวแรก "ja") → true
เอกสารที่สอง: "sam", "adam" ไม่อยู่ใน "john" → false
วิธีง่ายกว่า (MongoDB 4.2+): ใช้ $function หรือ $regex
// ใช้ $regex กับ $expr (รองรับ case-insensitive)
db.demo90.find({
$expr: {
$in: [true, { $map: { input: "$words", in: { $regexMatch: { input: "john", regex: "$$this" } } } }]
}
})
กรณีใช้จริง: Autocomplete, search suggestions, tag matching