Tùy chọn tốt nhất của bạn ở đây là chạy các truy vấn riêng biệt cho từng "Quốc gia" (lý tưởng nhất là song song) và trả về kết quả được kết hợp. Các truy vấn khá đơn giản và chỉ trả về 2 giá trị hàng đầu sau khi áp dụng sắp xếp trên giá trị xếp hạng và sẽ thực thi khá nhanh ngay cả khi bạn cần thực hiện nhiều truy vấn để có được kết quả hoàn chỉnh.
Khung tổng hợp không phù hợp cho điều này, bây giờ và thậm chí trong tương lai gần. Vấn đề là không có toán tử nào như vậy "giới hạn" kết quả của bất kỳ nhóm nào theo bất kỳ cách nào. Vì vậy, để làm điều này, về cơ bản bạn cần phải $push
tất cả nội dung vào một mảng và trích xuất các giá trị "n trên cùng" từ đó.
Các hoạt động hiện tại cần thiết để thực hiện điều đó khá khủng khiếp và vấn đề cốt lõi là kết quả có thể vượt quá giới hạn BSON 16MB cho mỗi tài liệu trên hầu hết các nguồn dữ liệu thực.
Ngoài ra còn có một n
sự phức tạp của điều này do bạn sẽ phải làm như thế nào ngay bây giờ. Nhưng chỉ để minh chứng với 2 mục:
db.collection.aggregate([
// Sort content by country and rating
{ "$sort": { "Country": 1, "rating": -1 } },
// Group by country and push all items, keeping first result
{ "$group": {
"_id": "$Country",
"results": {
"$push": {
"name": "$name",
"rating": "$rating",
"id": "$id"
}
},
"first": {
"$first": {
"name": "$name",
"rating": "$rating",
"id": "$id"
}
}
}},
// Unwind the array
{ "$unwind": "results" },
// Remove the seen result from the array
{ "$redact": {
"$cond": {
"if": { "$eq": [ "$results.id", "$first.id" ] },
"then": "$$PRUNE",
"else": "$$KEEP"
}
}},
// Group to return the second result which is now first on stack
{ "$group": {
"_id": "$_id",
"first": { "$first": "$first" },
"second": {
"$first": {
"name": "$results.name",
"rating": "$results.rating",
"id": "$results.id"
}
}
}},
// Optionally put these in an array format
{ "$project": {
"results": {
"$map": {
"input": ["A","B"],
"as": "el",
"in": {
"$cond": {
"if": { "$eq": [ "$$el", "A" ] },
"then": "$first",
"else": "$second"
}
}
}
}
}}
])
Điều đó có được kết quả nhưng nó không phải là một cách tiếp cận tuyệt vời và phức tạp hơn rất nhiều với các lần lặp lại cho các giới hạn cao hơn hoặc thậm chí khi các nhóm có thể có ít hơn n
kết quả trả về trong một số trường hợp.
Chuỗi phát triển hiện tại (3.1.x) kể từ khi viết có $slice
toán tử làm cho điều này đơn giản hơn một chút, nhưng vẫn có cùng một "kích thước" lỗi:
db.collection.aggregate([
// Sort content by country and rating
{ "$sort": { "Country": 1, "rating": -1 } },
// Group by country and push all items, keeping first result
{ "$group": {
"_id": "$Country",
"results": {
"$push": {
"name": "$name",
"rating": "$rating",
"id": "$id"
}
}
}},
{ "$project": {
"results": { "$slice": [ "$results", 2 ] }
}}
])
Nhưng về cơ bản cho đến khi khung tổng hợp có một số cách để "giới hạn" số lượng mặt hàng do $push
tạo ra hoặc toán tử "giới hạn" nhóm tương tự, thì khung tổng hợp không thực sự là giải pháp tối ưu cho loại vấn đề này.
Các truy vấn đơn giản như sau:
db.collection.find({ "Country": "USA" }).sort({ "rating": -1 }).limit(1)
Chạy cho từng quốc gia riêng biệt và lý tưởng là xử lý song song bằng vòng lặp sự kiện của chuỗi với kết quả kết hợp tạo ra phương pháp tối ưu nhất ngay bây giờ. Họ chỉ tìm nạp những gì cần thiết, đây là vấn đề lớn mà khung tổng hợp chưa thể xử lý trong việc phân nhóm như vậy.
Vì vậy, hãy tìm kiếm sự hỗ trợ để thực hiện "kết quả truy vấn kết hợp" này theo cách tối ưu nhất cho ngôn ngữ bạn đã chọn, vì nó sẽ ít phức tạp hơn và hiệu quả hơn nhiều so với việc ném điều này vào khung tổng hợp.