Giả sử bạn có một collection sales trong MongoDB với các tài liệu như sau:
{ "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-03-01T08:00:00Z") }
{ "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "date" : ISODate("2014-03-01T09:00:00Z") }
{ "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-03-15T09:00:00Z") }
{ "_id" : 4, "item" : "xyz", "price" : 5, "quantity" : 20, "date" : ISODate("2014-04-04T11:21:39.736Z") }
{ "_id" : 5, "item" : "abc", "price" : 10, "quantity" : 10, "date" : ISODate("2014-04-04T21:23:13.331Z") }
Truy vấn tổng hợp (Aggregation) trong MongoDB
Để nhóm dữ liệu theo ngày (tháng/ngày/năm) và tính tổng doanh thu, trung bình số lượng và số bản ghi, bạn có thể dùng pipeline aggregation như sau:
db.sales.aggregate([
{
$group: {
_id: {
year: { $year: "$date" },
month: { $month: "$date" },
day: { $dayOfMonth: "$date" }
},
totalRevenue: { $sum: { $multiply: ["$price", "$quantity"] } },
avgQty: { $avg: "$quantity" },
totalCount: { $sum: 1 }
}
}
])
Kết quả trả về sẽ giống như:
{ "_id": { "year": 2014, "month": 3, "day": 1 }, "totalRevenue": 40, "avgQty": 1.5, "totalCount": 2 }
{ "_id": { "year": 2014, "month": 3, "day": 15 }, "totalRevenue": 50, "avgQty": 10, "totalCount": 1 }
{ "_id": { "year": 2014, "month": 4, "day": 4 }, "totalRevenue": 200, "avgQty": 15, "totalCount": 2 }
Triển khai trong Go với thư viện mongo-go-driver
Sử dụng driver chính thức của MongoDB cho Go (go.mongodb.org/mongo-driver), bạn có thể viết đoạn mã sau để thực thi truy vấn trên:
package main
import (
"context"
"fmt"
"log"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type GroupResult struct {
ID bson.M `bson:"_id"`
TotalRevenue float64 `bson:"totalRevenue"`
AvgQty float64 `bson:"avgQty"`
TotalCount int32 `bson:"totalCount"`
}
func main() {
client, err := mongo.Connect(context.TODO(), options.Client().ApplyURI("mongodb://localhost:27017"))
if err != nil {
log.Fatal(err)
}
defer client.Disconnect(context.TODO())
coll := client.Database("testdb").Collection("sales")
pipeline := []bson.M{
{
"$group": bson.M{
"_id": bson.M{
"year": bson.M{"$year": "$date"},
"month": bson.M{"$month": "$date"},
"day": bson.M{"$dayOfMonth": "$date"},
},
"totalRevenue": bson.M{"$sum": bson.M{"$multiply": []string{"$price", "$quantity"}}},
"avgQty": bson.M{"$avg": "$quantity"},
"totalCount": bson.M{"$sum": 1},
},
},
}
cursor, err := coll.Aggregate(context.TODO(), pipeline)
if err != nil {
log.Fatal(err)
}
defer cursor.Close(context.TODO())
var results []GroupResult
if err = cursor.All(context.TODO(), &results); err != nil {
log.Fatal(err)
}
for _, res := range results {
fmt.Printf("%+v\n", res)
}
}
Một số lưu ý quan trọng
- Trường
_idtrong stage$grouplà bắt buộc. Nếu đặt_id: null, toàn bộ collection sẽ được gom thành một nhóm duy nhất. $sum: 1dùng để đếm số bản ghi. Có thể thay bằng giá trị khác nếu cần nhân hệ số.- Các biểu thức như
$year,$month,$dayOfMonthtrích xuất thành phần từ trường kiểuDate.