MongoDBにはまだこれを行うための本当に効率的な演算子がないため、これは実際には(まだ)複数のクエリで最も適切に処理されます。
MongoDB 3.2でもこのようなことができますが、明らかな「キャッチ」があります:
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] }
}}
])
そして明らかな問題は、何があっても、すべてを追加していることです。 グループ化された配列への「url」コンテンツの。これは、BSONの制限である16MBを超える可能性があります。そうではないかもしれませんが、「3つ」だけが必要な場合に「すべて」のコンテンツを追加するのはまだ少し無駄です。
そのため、それでも、上位10件の結果のそれぞれで「URL」を個別に実際にクエリする方がおそらくより実用的です。
これは、以下を示すnode.jsのリストです。
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
}
);
}
)
});
はい、それはデータベースへのより多くの呼び出しですが、実際にはわずか10 したがって、実際には問題ではありません。
本物 この解決策は、SERVER-9377で説明されています-$pushまたは$maxを拡張して、「top」を収集できるようにします"$groupフェーズの_idキーごとにN個の値 。これは有望な「進行中」ステータスであるため、積極的に取り組んでいます。
それが解決されると、単一の集計ステートメントが実行可能になります。それ以降、最初の$push
で結果の「url」を「制限」できるようになります。 事後に3つを除くすべてを削除するのではなく、3つのエントリだけに変更します。