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

วิธีสุ่มเอกสาร 2 รายการจาก Collection 6 รายการใน MongoDB

การสุ่มเอกสาร (Random Sampling) ใน MongoDB ด้วย $sample

ใช้ Aggregation Stage $sample เพื่อสุ่มเอกสารจาก Collection ได้อย่างมีประสิทธิภาพ โดยระบุ size คือจำนวนเอกสารที่ต้องการ

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

> db.twoRandomDocumentDemo.insertOne({"StudentId":10});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9ec9aad628fa4220163b87") }
> db.twoRandomDocumentDemo.insertOne({"StudentId":100});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9ec9add628fa4220163b88") }
> db.twoRandomDocumentDemo.insertOne({"StudentId":45});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9ec9b0d628fa4220163b89") }
> db.twoRandomDocumentDemo.insertOne({"StudentId":55});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9ec9b3d628fa4220163b8a") }
> db.twoRandomDocumentDemo.insertOne({"StudentId":5});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9ec9b7d628fa4220163b8b") }
> db.twoRandomDocumentDemo.insertOne({"StudentId":7});
{ "acknowledged" : true, "insertedId" : ObjectId("5c9ec9bad628fa4220163b8c") }

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

> db.twoRandomDocumentDemo.find();

ผลลัพธ์ (6 เอกสาร):

{ "_id" : ObjectId("5c9ec9aad628fa4220163b87"), "StudentId" : 10 }
{ "_id" : ObjectId("5c9ec9add628fa4220163b88"), "StudentId" : 100 }
{ "_id" : ObjectId("5c9ec9b0d628fa4220163b89"), "StudentId" : 45 }
{ "_id" : ObjectId("5c9ec9b3d628fa4220163b8a"), "StudentId" : 55 }
{ "_id" : ObjectId("5c9ec9b7d628fa4220163b8b"), "StudentId" : 5 }
{ "_id" : ObjectId("5c9ec9bad628fa4220163b8c"), "StudentId" : 7 }

สุ่ม 2 เอกสารจาก 6 (Run ครั้งที่ 1)

> db.twoRandomDocumentDemo.aggregate([{$sample: {size: 2}}]);

ผลลัพธ์ (ตัวอย่าง):

{ "_id" : ObjectId("5c9ec9b3d628fa4220163b8a"), "StudentId" : 55 }
{ "_id" : ObjectId("5c9ec9aad628fa4220163b87"), "StudentId" : 10 }

สุ่ม 2 เอกสารจาก 6 (Run ครั้งที่ 2 - ผลลัพธ์ต่างออกไป)

> db.twoRandomDocumentDemo.aggregate([{$sample: {size: 2}}]);

ผลลัพธ์ (ตัวอย่าง):

{ "_id" : ObjectId("5c9ec9add628fa4220163b88"), "StudentId" : 100 }
{ "_id" : ObjectId("5c9ec9b7d628fa4220163b8b"), "StudentId" : 5 }

คำอธิบาย $sample

  • {$sample: {size: N}} : สุ่ม N เอกสารจาก Collection
  • Algorithm: ใช้ Reservoir Sampling (เหมาะกับ Collection ใหญ่) หรือ Random Cursor (Collection เล็ก)
  • Non-deterministic: ผลลัพธ์ต่างกันทุกครั้งที่รัน
  • No Sort Order: ไม่รับประกันลำดับ

ข้อจำกัดและข้อควรระวัง

⚠️ ข้อจำกัดของ $sample

  • Size ต้อง <= 5% ของ Collection Size (สำหรับ Reservoir Sampling) มิฉะนั้นจะ Fallback เป็น Full Collection Scan
  • ไม่รองรับ Sharded Collection ต้องใช้ $sample บน mongos ได้แต่มีข้อจำกัด
  • ไม่สามารถใช้ $match ก่อน $sample ได้ (ต้อง $match ก่อน แล้ว $sample) - รองรับใน Pipeline
  • Replacement: Sampling แบบ Without Replacement (ไม่ซ้ำในรอบเดียวกัน)

ตัวอย่าง Pipeline ครบถ้วน: Filter แล้วค่อย Random

// สุ่ม 3 เอกสารจากเฉพาะ Active Users
db.users.aggregate([
    { $match: { status: "active", age: { $gte: 18 } } },
    { $sample: { size: 3 } },
    { $project: { _id: 1, name: 1, email: 1 } }
]);

วิธีสุ่มแบบเก่า (ก่อนมี $sample) - ไม่แนะนำ

// ใช้ $rand (MongoDB 4.4+) + sort + limit
db.collection.aggregate([
    { $addFields: { rand: { $rand: {} } } },
    { $sort: { rand: 1 } },
    { $limit: 2 }
]);

// ใช้ skip แบบสุ่ม (ไม่แนะนำ - ช้ามาก)
var count = db.collection.countDocuments();
var randomSkip = Math.floor(Math.random() * count);
db.collection.find().skip(randomSkip).limit(2);

ใช้ $sample กับ $match และ $project

db.products.aggregate([
    { $match: { category: "electronics", price: { $lt: 1000 } } },
    { $sample: { size: 5 } },
    { $project: { _id: 0, name: 1, price: 1, image: 1 } }
]);

การใช้งานใน Application (Node.js)

const samples = await db.collection('products')
    .aggregate([
        { $match: { inStock: true } },
        { $sample: { size: 10 } }
    ])
    .toArray();

$sample เป็นวิธีที่มีประสิทธิภาพและง่ายที่สุดสำหรับ Random Sampling ใน MongoDB เวอร์ชันปัจจุบัน