5

次のようなサブドキュメントを含むドキュメントがあります。

{ 
    "name" : "some name1" 
    "like" : [      
            {  "date" : ISODate("2012-11-30T19:00:00Z") },
            {  "date" : ISODate("2012-12-02T19:00:00Z") },     
            {  "date" : ISODate("2012-12-01T19:00:00Z") },
            {  "date" : ISODate("2012-12-03T19:00:00Z") } 
    ]       
}

「最もいいね」されたドキュメント (過去 7 日間の平均値) を取得して、その数で並べ替えることはできますか?

4

3 に答える 3

11

この問題を解決するには、いくつかの方法があります。ここで取り上げるソリューションでは、mongodb の集計フレームワークを使用します。まず、問題を解決する集計パイプラインを次に示します。次に、コマンドで何が起こっているかの説明/内訳を示します。

db.testagg.aggregate( 
    { $unwind : '$likes' }, 
    { $group : {  _id : '$_id', numlikes : { $sum : 1 }}}, 
    { $sort : { 'numlikes' : 1}})

このパイプラインには 3 つの主要なコマンドがあります。

1) アンワインド: これにより、「いいね」フィールドが分​​割され、ドキュメントごとに 1 つの「いいね」要素が存在するようになります

2) グループ: _id フィールドを使用してドキュメントを再グループ化し、見つかったドキュメントごとに numLikes フィールドをインクリメントします。これにより、numLikes は、以前に "likes" にあった要素の数に等しい数で埋められます。

3) 並べ替え: 最後に、numLikes に基づいて、戻り値を昇順に並べ替えます。私が実行したテストでは、このコマンドの出力は次のとおりです。

{"result" : [
    {
        "_id" : 1,
        "numlikes" : 1
    },
    {
        "_id" : 2,
        "numlikes" : 2
    },
    {
        "_id" : 3,
        "numlikes" : 3
    },
    {
        "_id" : 4,
        "numlikes" : 4
    }....

これは、次の方法で挿入されたデータ用です。

for (var i=0; i < 100; i++) {
    db.testagg.insert({_id : i})
    for (var j=0; j < i; j++) {
        db.testagg.update({_id : i}, {'$push' : {'likes' : j}})
    }
}

日付範囲を選択する問題を回避するため、これはあなたの質問に完全に答えるものではないことに注意してください。

もちろん、この問題を解決する方法は他にもあります。1 つの解決策は、すべての並べ替えと操作をクライアント側で行うことです。これは、必要な情報を取得するための 1 つの方法にすぎません。

編集: これがやや面倒だと思われる場合は、集約フレームワークに $size 演算子を追加するためのチケットがあります。興味がある場合は、この新しい演算子の追加を試してスピードアップするために、これを見て賛成票を投じることをお勧めします。

https://jira.mongodb.org/browse/SERVER-4899

于 2012-12-24T18:31:24.203 に答える
8

より良い解決策は、このドキュメントのいいね! の数を記録するカウント フィールドを保持することです。集約を使用してこれを行うことはできますが、パフォーマンスはあまり良くない可能性があります。カウント フィールドにインデックスがあると、読み取り操作が高速になり、アトミック操作を使用して、新しいいいね! を挿入するときにカウンターをインクリメントできます。

于 2012-12-24T18:31:53.090 に答える
1

これを使用して、mongodb v3.4 以降、次のように上記の集計クエリを簡素化できます。

> db.test.aggregate([
    { $unwind: "$like" },
    { $sortByCount: "$_id" }
 ]).pretty()

{ "_id" : ObjectId("5864edbfa4d3847e80147698"), "count" : 4 }

また、@ACE が言ったように、代わりに射影内で $size を使用できるようになりました。

db.test.aggregate([
    { $project: { count: { $size : "$like" } } }
]);

{ "_id" : ObjectId("5864edbfa4d3847e80147698"), "count" : 4 }
于 2016-12-29T16:55:10.977 に答える