Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> MongoDB

Cách lấy 2 tài liệu ngẫu nhiên từ collection 6 document trong MongoDB

Giới thiệu

Để lấy ngẫu nhiên (random) N tài liệu từ collection, MongoDB cung cấp stage aggregation $sample (từ version 3.2). Đây là cách hiệu quả và đơn giản nhất.

Cú pháp

db.collection.aggregate([ { $sample: { size: N } } ]);

Ví dụ minh họa

1. Tạo collection 6 document

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

2. Lấy 2 document ngẫu nhiên (Lần 1)

> db.ngauNhien2Doc.aggregate([ { $sample: { size: 2 } } ]);
{ "_id" : ObjectId("5c9ec9b3d628fa4220163b8a"), "MaSinhVien" : 55 }
{ "_id" : ObjectId("5c9ec9aad628fa4220163b87"), "MaSinhVien" : 10 }

3. Chạy lại lần 2 - Kết quả khác (ngẫu nhiên thực sự)

> db.ngauNhien2Doc.aggregate([ { $sample: { size: 2 } } ]);
{ "_id" : ObjectId("5c9ec9add628fa4220163b88"), "MaSinhVien" : 100 }
{ "_id" : ObjectId("5c9ec9b7d628fa4220163b8b"), "MaSinhVien" : 5 }

Chi tiết về $sample

Đặc điểmMô tả
AlgorithmReservoir sampling (lấy mẫu hồ chứa)
Hiệu suấtO(N) - quét toàn bộ collection
Độ chính xácXấp xỉ (approximate) cho collection lớn
Size > collection sizeTrả về tất cả document (không lặp)
Sharded clusterHỗ trợ từ MongoDB 4.4+

Lưu ý quan trọng

  • $sample phải là **stage đầu tiên** trong pipeline (trước $match, $project...)
  • Không thể dùng index - luôn collection scan
  • Với collection lớn (>100k docs), cân nhắc cách khác để tránh chậm
  • Kết quả **không đảm bảo phân bố đều** hoàn hảo trên collection cực lớn

Phương án thay thế cho collection lớn

Cách 1: Random skip (nếu có index trên _id)

var count = db.collection.countDocuments();
var randomSkip = Math.floor(Math.random() * count);
db.collection.find().skip(randomSkip).limit(2);

Cách 2: Pre-computed random field

// Thêm trường random khi insert
db.collection.insertOne({ ..., random: Math.random() });

// Query
db.collection.find({ random: { $gte: Math.random() } }).limit(2);

Cách 3: Lấy _id ngẫu nhiên từ application

// App code: lấy count, random N offset, query bằng _id
const count = await coll.countDocuments();
const randomIds = Array.from({length: 2}, () => Math.floor(Math.random() * count));
const docs = await coll.find({ _id: { $in: randomIds } }).toArray();