Điều này thực sự (vẫn) được xử lý tốt nhất bởi nhiều truy vấn, vì MongoDB thực sự "vẫn" chưa có các toán tử thực sự hiệu quả để thực hiện việc này.
Tuy nhiên, bạn có thể làm điều gì đó như thế này với MongoDB 3.2, nhưng rõ ràng có những điểm "bắt bài":
db.Books.aggregate([
{ "$group": {
"_id": "$company",
"count": { "$sum": 1 },
"urls": {
"$push": "$url"
}
}},
{ "$sort": { "count": -1 } },
{ "$limit": 10 },
{ "$project": {
"count": 1,
"urls": { "$slice": ["$urls",0, 3] }
}}
])
Và vấn đề rõ ràng là không có vấn đề gì, bạn vẫn đang thêm tất cả của nội dung "url" vào mảng được nhóm. Điều này có khả năng vượt quá giới hạn BSON là 16MB. Có thể không, nhưng vẫn hơi lãng phí nếu thêm "tất cả" nội dung khi bạn chỉ muốn "ba" trong số đó.
Vì vậy, thậm chí sau đó có lẽ thực tế hơn nếu chỉ thực sự truy vấn các "url" riêng biệt trên mỗi kết quả trong số 10 kết quả hàng đầu.
Đây là danh sách cho node.js minh chứng:
var async = require('async'),
mongodb = require('mongodb'),
MongoClient = mongodb.MongoClient;
MongoClient.connect("mongodb://localhost/test",function(err,db) {
if (err) throw err;
// Get the top 10
db.collection("Books").aggregate(
[
{ "$group": {
"_id": "$company",
"count": { "$sum": 1 }
}},
{ "$sort": { "count": -1 } },
{ "$limit": 10 }
],function(err,results) {
if (err) throw err;
// Query for each result and map query response as urls
async.map(
results,
function(result,callback) {
db.collection("Books").find({
"company": result.company
}).limit(3).toArray(function(err,items) {
result.urls = items.map(function(item) {
return item.url;
});
callback(err,result);
})
},
function(err,results) {
if (err) throw err;
// each result entry has 3 urls
}
);
}
)
});
Có, đó là nhiều lệnh gọi đến cơ sở dữ liệu hơn, nhưng thực sự là chỉ có mười và do đó không thực sự là một vấn đề.
thực tế giải pháp cho vấn đề này được đề cập trong SERVER-9377 - Mở rộng $ push hoặc $ max để cho phép thu thập "đầu trang "N giá trị cho mỗi khóa _id trong giai đoạn $ nhóm . Điều này có trạng thái "Đang xử lý" đầy hứa hẹn, vì vậy nó đang được tích cực làm việc.
Khi điều đó được giải quyết, thì một câu lệnh tổng hợp duy nhất trở nên khả thi, vì từ đó bạn có thể "giới hạn" các "url" kết quả trong $push
intial chỉ ba mục nhập, thay vì xóa tất cả trừ ba mục sau thực tế.