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

เปรียบเทียบ Multiple Properties ใน MongoDB ด้วย $where

Operator $where ใน MongoDB อนุญาตให้ใช้ JavaScript expression ในการ query เหมาะสำหรับเปรียบเทียบ field กับ field (cross-field comparison) ที่ operator ธรรมดาทำไม่ได้

สร้างคอลเลกชันและข้อมูลตัวอย่าง

> db.demo223.insertOne({"Scores":[56,78]});
{ "acknowledged" : true, "insertedId" : ObjectId("5e3ee4ca03d395bdc2134730") }
> db.demo223.insertOne({"Scores":[88,45]});
{ "acknowledged" : true, "insertedId" : ObjectId("5e3ee4d103d395bdc2134731") }
> db.demo223.insertOne({"Scores":[98,79]});
{ "acknowledged" : true, "insertedId" : ObjectId("5e3ee4d803d395bdc2134732") }

แสดงข้อมูลทั้งหมด

> db.demo223.find();

ผลลัพธ์: 3 เอกสาร แต่ละอันมี Scores array 2 elements

Query เปรียบเทียบ Scores[0] > Scores[1] ด้วย $where

> db.demo223.find({ $where : "this.Scores[0] > this.Scores[1]" });

ผลลัพธ์

{ "_id" : ObjectId("5e3ee4d103d395bdc2134731"), "Scores" : [ 88, 45 ] }
{ "_id" : ObjectId("5e3ee4d803d395bdc2134732"), "Scores" : [ 98, 79 ] }

เอกสารที่ 1: 56 > 78 = false (ไม่ผ่าน)
เอกสารที่ 2: 88 > 45 = true (ผ่าน)
เอกสารที่ 3: 98 > 79 = true (ผ่าน)

คำอธิบาย $where:

  • this = current document
  • เขียน JavaScript expression คืนค่า true/false
  • เข้าถึง field ได้แบบ this.fieldName หรือ this["field-name"]
  • เข้าถึง array element: this.Scores[0]

⚠️ ข้อจำกัดและคำเตือนสำคัญ

วิธีทดแทน $where ด้วย Aggregate (แนะนำ)

db.demo223.aggregate([
  { $project: {
    Scores: 1,
    firstGtSecond: { $gt: [{ $arrayElemAt: ["$Scores", 0] }, { $arrayElemAt: ["$Scores", 1] }] }
  }},
  { $match: { firstGtSecond: true }},
  { $project: { firstGtSecond: 0 }}
])

ใช้ $expr (MongoDB 3.6+) - ใช้ Index ได้

db.demo223.find({
  $expr: { $gt: [{ $arrayElemAt: ["$Scores", 0] }, { $arrayElemAt: ["$Scores", 1] }] }
})

ข้อดี $expr: ใช้ index ได้, รองรับ sharding, เร็วกว่า $where มาก

เมื่อไหร่ควรใช้ $where

  • Logic ที่ซับซ้อนมากที่ $expr ทำไม่ได้
  • Ad-hoc query ใน shell (one-time)
  • Dataset เล็ก (< 10k docs)

สรุป: หลีกเลี่ยง $where ใน production ใช้ $expr + $arrayElemAt แทนสำหรับ cross-field comparison

ปัญหารายละเอียด
PerformanceSlow - ต้อง evaluate JavaScript ทุก document ไม่ใช้ index
SecurityRisk injection - ไม่ควรใช้ user input ตรงๆ
ConcurrencySingle-threaded JS engine บล็อก operations อื่น
Shardingไม่รองรับ sharded collections