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

Conditional $first ใน MongoDB Aggregation: ข้าม Null ด้วย $match

ใช้ $match กรองเอกสารที่ไม่ใช่ Null ก่อน แล้วค่อย $group พร้อม $first เพื่อเอาค่าแรกที่ไม่ใช่ Null (Conditional First)

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

> db.conditionalFirstDemo.insertOne({_id: 100, "StudentName": "Chris", "StudentSubject": null});
{ "acknowledged": true, "insertedId": 100 }
> db.conditionalFirstDemo.insertOne({_id: 101, "StudentName": "Chris", "StudentSubject": null});
{ "acknowledged": true, "insertedId": 101 }
> db.conditionalFirstDemo.insertOne({_id: 102, "StudentName": "Chris", "StudentSubject": "MongoDB"});
{ "acknowledged": true, "insertedId": 102 }
> db.conditionalFirstDemo.insertOne({_id: 103, "StudentName": "Chris", "StudentSubject": "MongoDB"});
{ "acknowledged": true, "insertedId": 103 }
> db.conditionalFirstDemo.insertOne({_id: 104, "StudentName": "Chris", "StudentSubject": null});
{ "acknowledged": true, "insertedId": 104 }

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

> db.conditionalFirstDemo.find();

ผลลัพธ์: 5 เอกสาร สลับ Null และ MongoDB

Aggregation: ข้าม Null แล้วเอา $first

> db.conditionalFirstDemo.aggregate([
  {$match: {"StudentSubject": {$ne: null}}},
  {$group: {_id: "$StudentName", "StudentSubject": {$first: "$StudentSubject"}}}
]);

ผลลัพธ์: ได้ MongoDB (ค่าแรกที่ไม่ใช่ Null ตามลำดับ _id)

{"_id": "Chris", "StudentSubject": "MongoDB"}

การทำงาน

  1. $match: {StudentSubject: {$ne: null}} กรองเอาเฉพาะเอกสารที่ StudentSubject ไม่เป็น Null (เหลือ _id 102, 103)
  2. $group จัดกลุ่มตาม StudentName (Chris)
  3. $first เอาค่าแรกในกลุ่ม (ตามลำดับ Natural/Order) = MongoDB

เทคนิคเพิ่มเติม

  • เรียงลำดับก่อน Group (สำคัญ! $first ขึ้นกับ Sort Order):
    db.coll.aggregate([
      {$match: {field: {$ne: null}}},
      {$sort: {date: 1}},  // เรียงเก่าไปใหม่ หรือใหม่ไปเก่า
      {$group: {_id: "$key", firstValue: {$first: "$field"}}}   
    ]);
  • ใช้ $last แทน $first หากต้องการค่าสุดท้าย
  • $firstN / $lastN (MongoDB 5.2+): เอา N ค่าแรก/สุดท้าย

กรณีซับซ้อน: First Non-null ใน Array

db.coll.aggregate([
  {$unwind: "$arrayField"},
  {$match: {"arrayField.value": {$ne: null}}},
  {$group: {_id: "$_id", firstNonNull: {$first: "$arrayField.value"}}}
]);

หมายเหตุ

  • โดย Default $first จะเอาค่าแรกตามลำดับ Document ใน Shard/Collection (ไม่ Guarantee Order)
  • ต้องใช้ $sort ก่อน $group เสมอหากต้องการ Order เฉพาะ
  • $match วางก่อน $sort เพื่อประสิทธิภาพ (Reduce Documents to Sort)