Tính trung bình số lượng document ghi nhận mỗi ngày
Sử dụng aggregation với $group tìm ngày cũ nhất, $sum tổng giá trị, $project tính toán số ngày và trung bình.
1. Dữ liệu: DueDate + Value
> db.demo451.insertOne({ DueDate: new ISODate("2020-03-15T10:50:35.000Z"), Value: 10 });
> db.demo451.insertOne({ DueDate: new ISODate("2020-03-14T10:50:35.000Z"), Value: 10 });
> db.demo451.insertOne({ DueDate: new ISODate("2020-03-13T10:50:35.000Z"), Value: 10 });
2. Pipeline tính trung bình ngày
> db.demo451.aggregate([
{ $match: { DueDate: { $lt: new ISODate() } } },
{ $group: {
_id: null,
olderDate: { $min: "$DueDate" },
sumValue: { $sum: "$Value" }
}},
{ $project: {
_id: 0,
averageValue: {
$divide: [
"$sumValue",
{ $divide: [
{ $subtract: [new ISODate(), "$olderDate"] },
1000 * 60 * 60 * 24 // ms → days
]}
]
}
}}
]);
3. Kết quả
{ "averageValue": 2.475558456547562 }
Giải thích công thức
averageValue = sumValue / ((now - oldestDate) / ms_per_day)
sumValue: Tổng Value = 30olderDate: Ngày sớm nhất = 2020-03-13now - olderDate: Khoảng cách mili-giây từ 13/3 đến hiện tại- Chia cho
86,400,000(ms/ngày) → số ngày - 30 / số ngày ≈ 2.48 document/ngày
Cách tốt hơn: Group theo ngày thực tế
db.demo451.aggregate([
{ $match: { DueDate: { $lt: new ISODate() } } },
{ $group: {
_id: { $dateToString: { format: "%Y-%m-%d", date: "$DueDate" } },
dailyCount: { $sum: 1 },
dailySum: { $sum: "$Value" }
}},
{ $group: {
_id: null,
avgDailyCount: { $avg: "$dailyCount" },
avgDailySum: { $avg: "$dailySum" },
days: { $sum: 1 }
}}
]);
Cách này tính trung bình dựa trên các ngày thực sự có dữ liệu, không giả định dữ liệu đều đặn mỗi ngày.
Lưu ý
- Ví dụ gốc dùng
new ISODate()trong pipeline → kết quả thay đổi theo thời gian chạy - Trong production, hãy truyền tham số ngày cố định từ application
- Dùng
$dateTrunc(MongoDB 5.0+) để gom nhóm theo ngày/giờ chính xác hơn