บทนี้นำเสนอคำอธิบายอย่างละเอียดเกี่ยวกับการวิเคราะห์ทางสถิติของ MongoDB ซึ่งทำได้หลักโดยใช้ Aggregation Pipeline มันคล้ายกับคำสั่ง "group by" ใน SQL เราสามารถทำการวิเคราะห์ทางสถิติใน MongoDB shell โดยใช้ฟังก์ชัน db.collection.aggregate()

ขั้นตอนพื้นฐานของการวิเคราะห์

  • ใช้ $match เพื่อกรองข้อมูลเป้าหมาย
  • ใช้ $group เพื่อจัดกลุ่มและคำนวณข้อมูล
  • ใช้ $sort เพื่อเรียงลำดับผลลัพธ์ (ตัวเลือก)

ข้อมูลทดสอบ

ข้อมูลในคอลเลคชัน orders มีดังนี้

{ _id: 1, cust_id: "abc1", ord_date: ISODate("2012-11-02T17:04:11.102Z"), status: "A", amount: 50 }
{ _id: 2, cust_id: "xyz1", ord_date: ISODate("2013-10-01T17:04:11.102Z"), status: "A", amount: 100 }
{ _id: 3, cust_id: "xyz1", ord_date: ISODate("2013-10-12T17:04:11.102Z"), status: "D", amount: 25 }
{ _id: 4, cust_id: "xyz1", ord_date: ISODate("2013-10-11T17:04:11.102Z"), status: "D", amount: 125 }
{ _id: 5, cust_id: "abc1", ord_date: ISODate("2013-11-12T17:04:11.102Z"), status: "A", amount: 25 }

ฟังก์ชัน aggregate

db.collection.aggregate(pipeline) คำอธิบาย:

  • pipeline รับพารามิเตอร์เป็นอาร์เรย์ ที่แต่ละองค์แทนสเตจการประมวลผล

ตัวอย่าง

db.orders.aggregate([
                     { $match: { status: "A" } },  // สเตจแรก
                     { $group: { _id: "$cust_id", total: { $sum: "$amount" } } },   // สเตจที่สอง
                     { $sort: { total: -1 } }  // สเตจที่สาม (ตัวเลือก)
                   ])

SQL เทียบเท่า

select sum(amount) as total from orders 
        where status="A" 
        group by cust_id 
        order by total desc

สเตจ $match

รูปแบบ:

{ $match: { <query> } }

คำอธิบาย:

  • <query> เงื่อนไขคิวรี MongoDB

ใช้เพื่อตั้งเงื่อนไขคิวรี ถ้า $match ถูกละเลย นั้นหมายความว่าการคิวรีข้อมูลทั้งหมด

เกร้ด: หากคุณไม่เคยใช้กับการคิวรีเชิงฐานข้อมูล MongoDB กรุณาอ้างถึงบทที่ผ่านมา

สเตจ $group

คล้ายกับคำสั่ง group by ใน SQL ใช้เพื่อจัดกลุ่มข้อมูลและทำการคำนวณทางสถิติต่าง ๆ บนข้อมูลที่จัดกลุ่ม

การใช้งานพื้นฐานของ $group

รูปแบบ:

{
  $group:
    {
      _id: <expression>, // เงื่อนไขการจัดกลุ่ม เช่น: จัดกลุ่มโดยใด
      <field1>: { <accumulator1> : <expression1> },  // การดำเนินการคำนวณ คุณสามารถเพิ่มการดำเนินการคำนวณ N ตัว
      ...
    }
 }

คำอธิบาย:

  • - ชื่อของตัวชี้วัดสถิติแบบกำหนดเอง สามารถเป็น N ในรวม
  • - ฟังก์ชันการคำนวณ คล้ายกับการบวก หาค่าเฉลี่ยและฟังก์ชันการคำนวณอื่น ๆ ของ SQL ต่างกันที่ฟังก์ชันการคำนวณของ MongoDB จะถูกตั้งชื่อด้วยเครื่องหมาย $ เช่น: $sum, $avg
  • - พารามิเตอร์ของฟังก์ชันการคำนวณ โดยธรรมชาติคือค่าของฟิลด์ที่ต้องการนับ การอ้างถึงฟิลด์ของเอกสารโดยใช้รูปแบบ "$ชื่อฟิลด์"

ตัวอย่าง:

db.orders.aggregate([
                     {
					 	$group: { 
							_id: "$cust_id",
							total: { $sum: "$amount" }, // เพิ่มตัวชี้วัดแรกที่คำนวณได้ total โดยใช้ตัวดำเนินการผลรวม $sum
							amount_avg: {$avg: "$amount"}  // เพิ่มตัวชี้วัดที่คำนวณได้สอง ค่าเฉลี่ย amount_avg โดยใช้ตัวดำเนินการคำนวณเฉลี่ย $avg
						} 
					}
               ])

ผลลัพธ์:

{ "_id" : "abc1", "total" : 75, "amount_avg" : 37.5 }
{ "_id" : "xyz1", "total" : 250, "amount_avg" : 83.33333333333333 }

SQL เทียบเท่า:

select 
	sum(amount) as  total,
	avg(amount) as amount_avg
from orders 
group by cust_id

ฟังก์ชันการรวมกลุ่ม $group

ฟังก์ชันการรวมกลุ่มชนิดที่ใช้บ่อยสำหรับ $group มีดังนี้:

ตัวดำเนินการ คำอธิบาย ตัวอย่าง
$avg คำนวณค่าเฉลี่ย {$avg: "$amount"}
$sum ผลรวม {$sum: "$amount"}
$max ค่าสูงสุด {$max: "$amount"}
$min ค่าต่ำสุด {$min: "$amount"}
$first คืนค่าข้อมูลหลังจากรวมกลุ่ม คือเนื้อหาของเอกสารแรก {$first: "$amount"}
$last คืนค่าข้อมูลหลังจากรวมกลุ่ม คือเนื้อหาของเอกสารสุดท้าย {$last: "$amount"}
$push คืนค่าข้อมูลหลังจากรวมกลุ่ม { $push: { ord_date: "$ord_date", amount: "$amount" }
$addToSet คืนค่าข้อมูลหลังจากรวมกลุ่ม ต่างจาก $push โดยที่มันจะเอาค่าซ้ำออก { $addToSet: "$amount" }

ตัวอย่างการใช้งาน $push

db.orders.aggregate(
   [
     {
       $group:
         {
           _id: "$cust_id",
           all: { $push: { ord_date: "$ord_date", amount: "$amount" } } // ค่าของฟิลด์ ord_date และ amount
         }
     }
   ]
)

ผลลัพธ์

{ "_id" : "abc1", "all" : [ { "ord_date" : "2021-04-18 00:00:00", "amount" : 50 }, { "ord_date" : "2021-04-21 00:00:00", "amount" : 25 } ] }
{ "_id" : "xyz1", "all" : [ { "ord_date" : "2021-04-18 00:00:00", "amount" : 100 }, { "ord_date" : "2021-04-20 00:00:00", "amount" : 25 }, { "ord_date" : "2021-04-21 00:00:00", "amount" : 125 } ] }

ตัวอย่างการใช้งาน $addToSet

db.orders.aggregate(
   [
     {
       $group:
         {
           _id: "$cust_id",
           all_amount: { $addToSet: "$amount" } // คืนค่าทั้งหมดของค่า amount ที่แตกต่างกัน
         }
     }
   ]
)

ผลลัพธ์

{ "_id" : "abc1", "all_amount" : [ 25, 50 ] }
{ "_id" : "xyz1", "all_amount" : [ 100, 25, 125 ] }

$sort:

ขั้นตอน $sort มักถูกวางไว้ที่ท้ายเพื่อเรียงลำดับข้อมูลที่รวมกัน

รูปแบบ:

{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }

อธิบาย:

  • , - ชื่อของฟิลด์ที่จะเรียงลำดับ รองรับหลายฟิลด์
  • - ทิศทางของการเรียงลำดับ -1 สำหรับการเรียงจากมากไปหาน้อย 1 สำหรับการเรียงจากน้อยไปหามาก

ตัวอย่าง:

db.orders.aggregate([
                     { $match: { status: "A" } },
                     { $group: { _id: "$cust_id", total: { $sum: "$amount" } } },
                     { $sort: { total: -1 } }
                   ])

การแบ่งหน้าข้อมูลที่รวมกัน

เราสามารถทำการแบ่งหน้าโดยใช้ตัวดำเนินการ $limit และ $skip

ตัวอย่าง:

db.orders.aggregate([
                     { $match: { status: "A" } },
                     { $group: { _id: "$cust_id", total: { $sum: "$amount" } } },
                     { $sort: { total: -1 } },
					 { $limit: 5 }, // จำกัดจำนวนรายการที่คืนค่า คล้ายกับขนาดหน้าในการแบ่งหน้า
					 { $skip: 1 } // ข้ามจำนวนรายการบางรายการ คล้ายกับออฟเซ็ตใน SQL
                   ])