Dette håndteres (stadig) bedst af flere forespørgsler, da MongoDB virkelig "stadig" ikke har de virkelig effektive operatører til at gøre dette endnu.
Du kan dog gøre noget som dette med MongoDB 3.2, men der er åbenlyse "fangster":
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] }
}}
])
Og det åbenlyse problem er, at uanset hvad, tilføjer du stadig alle af "url"-indholdet i det grupperede array. Dette har potentiale til at overskride BSON-grænsen på 16 MB. Måske ikke, men det er stadig lidt spild at tilføje "alt" indhold, når du kun vil have "tre" af dem.
Så selv da er det nok mere praktisk rent faktisk at forespørge efter "webadresserne" separat på hvert af de 10 bedste resultater.
Her er en liste for node.js, der demonstrerer:
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
}
);
}
)
});
Ja, det er flere opkald til databasen, men det er virkelig kun ti og derfor ikke rigtig et problem.
Det rigtige opløsning for dette er dækket af SERVER-9377 - Forlæng $push eller $max for at tillade indsamling af "top " N værdier pr. _id nøgle i $group fase . Dette har den lovende "I gang"-status, så der arbejdes aktivt på det.
Når det er løst, bliver en enkelt aggregeringssætning levedygtig, da du da ville være i stand til at "begrænse" de resulterende "webadresser" i den indledende $push
til kun tre poster, i stedet for at fjerne alle undtagen tre efter kendsgerningen.