Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> MongoDB

วิธีค้นหาเอกสาร MongoDB ที่ลึก 2 ระดับ (Two-level Deep)


ใช้ $where กับ JavaScript Function สำหรับ Query แบบ Dynamic

เมื่อโครงสร้างข้อมูลมีฟิลด์ซ้อนที่ไม่คงที่ (dynamic keys) ใช้ $where พร้อม JavaScript function วนลูปตรวจสอบทุกระดับ

ตัวอย่างข้อมูล (2 ระดับ: FirstPosition, SecondPosition)

> db.demo468.insertOne({
  "_id": new ObjectId(),
  "FirstPosition": { "StudentName": "Chris", "StudentAge": 23 },
  "SecondPosition": { "StudentName": "David", "StudentAge": 20 }
});
> db.demo468.insertOne({
  "_id": new ObjectId(),
  "FirstPosition": { "StudentName": "Carol", "StudentAge": 21 },
  "SecondPosition": { "StudentName": "John", "StudentAge": 22 }
});

Query หาเอกสารที่มี StudentName = "John" ในระดับไหนก็ได้

> db.demo468.find({
  $where: function() {
    for (var i in this) {
      if (this[i]["StudentName"] == "John") {
        return true;
      }
    }
    return false;
  }
});

ผลลัพธ์

{ "_id": ObjectId(...), "FirstPosition": { "StudentName": "Carol", "StudentAge": 21 }, "SecondPosition": { "StudentName": "John", "StudentAge": 22 } }

ข้อควรระวังกับ $where

  • ช้า - ต้อง evaluate JavaScript ทุกเอกสาร ไม่ใช้ index
  • Security risk - JavaScript injection หากรับ input จาก user
  • Deprecated trend - แนะนำให้ redesign schema หรือใช้ aggregation แทน

ทางเลือกที่ดีกว่า (Schema Redesign)

// แปลงเป็นอาร์เรย์ positions
{ "positions": [
  { "type": "FirstPosition", "StudentName": "Chris", "StudentAge": 23 },
  { "type": "SecondPosition", "StudentName": "David", "StudentAge": 20 }
]}

// แล้ว query ด้วย $elemMatch (เร็ว, ใช้ index ได้)
db.collection.find({ "positions": { $elemMatch: { "StudentName": "John" } } });

Aggregation Alternative (MongoDB 4.4+)

db.demo468.aggregate([
  { $project: {
      matched: { $gt: [{ $size: { $filter: { input: { $objectToArray: "$$ROOT" }, as: "kv", cond: { $eq: ["$$kv.v.StudentName", "John"] } } } }, 0] }
  }},
  { $match: { matched: true } }
]);