To naprawdę (nadal) najlepiej radzą sobie z wieloma zapytaniami, ponieważ MongoDB naprawdę „nadal” nie ma naprawdę wydajnych operatorów, aby to zrobić.
Możesz zrobić coś takiego z MongoDB 3.2, ale są oczywiste "haczyki":
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] }
}}
])
A oczywistym problemem jest to, że bez względu na wszystko, nadal dodajesz wszystkie zawartości „url” do zgrupowanej tablicy. Może to potencjalnie przekroczyć limit BSON wynoszący 16 MB. Może nie, ale wciąż trochę marnotrawstwem jest dodawanie „wszystkich” treści, gdy chcesz tylko „trzech”.
Więc nawet wtedy prawdopodobnie bardziej praktyczne jest po prostu zapytanie o „adresy URL” osobno w każdym z 10 najlepszych wyników.
Oto lista dla node.js, która pokazuje:
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
}
);
}
)
});
Tak, to więcej połączeń do bazy danych, ale tak naprawdę jest to tylko dziesięć i dlatego tak naprawdę nie stanowi problemu.
Prawdziwe Rozwiązanie tego problemu jest opisane w SERVER-9377 - Rozszerz $push lub $max, aby umożliwić zbieranie N wartości na klucz _id w fazie $group . Ma on obiecujący status „W toku”, więc aktywnie nad nim pracujemy.
Po rozwiązaniu tego problemu pojedyncza instrukcja agregacji staje się realna, ponieważ wtedy można „ograniczyć” wynikowe „adresy URL” w początkowym $push
do tylko trzech wpisów, zamiast usuwać wszystkie oprócz trzech po fakcie.