3

mongodb にドキュメントのコレクションがあり、それぞれにドキュメントを所有するグループを参照する「グループ」フィールドがあります。ドキュメントは次のようになります。

{
  group: <objectID>
  name: <string>
  contents: <string>
  date: <Date>
}

グループごとに最新の N 個のドキュメントを返すクエリを作成したいと思います。たとえば、5 つのグループがあり、それぞれに 20 のドキュメントがあるとします。各グループの上位 3 件を返すクエリを作成すると、各グループから 3 件ずつ、合計 15 件のドキュメントが返されます。別のグループに 4 番目の新しいグループがある場合でも、各グループには 3 が割り当てられます。

SQL の世界では、このタイプのクエリは「partition by」とカウンターで行われると思います。N個のグループに対してN + 1個の個別のクエリを実行する以外に、mongodbにそのようなものはありますか?

4

2 に答える 2

6

集約フレームワークを使用してこれを行うことはまだできません。各グループの $max またはトップ日付の値を取得できますが、集約フレームワークにはまだ上位 N を累積する方法がなく、ドキュメント全体を結果セットにプッシュする方法もありません。 (個々のフィールドのみ)。

そのため、MapReduce に頼る必要があります。これは機能するものですが、多くのバリアントがあると確信しています(すべて、特定の属性に基づいてオブジェクトの配列をソートする必要があります。この質問の回答の1つからソリューションを借りました。

Map 関数 - グループ名をキーとして出力し、残りのドキュメント全体を値として出力しますが、グループごとに結果の配列を蓄積しようとするため、配列を含むドキュメントとして出力します。

map = function () { 
    emit(this.name, {a:[this]}); 
}

reduce 関数は、同じグループに属するすべてのドキュメントを (concat を介して) 1 つの配列に蓄積します。日付をチェックして上位 5 つの配列要素のみを保持するように reduce を最適化する場合、finalize 関数は必要なく、mapreduce の実行中に使用するメモリが少なくなることに注意してください (これも高速になります)。

reduce = function (key, values) {
    result={a:[]};
    values.forEach( function(v) {
        result.a = v.a.concat(result.a);
    } );
    return result;
}

各キーのすべての値を保持しているので、キーごとに最新の 5 つの要素のみを引き出すファイナライズ関数が必要です。

final = function (key, value) {
      Array.prototype.sortByProp = function(p){
       return this.sort(function(a,b){
       return (a[p] < b[p]) ? 1 : (a[p] > b[p]) ? -1 : 0;
      });
    }

    value.a.sortByProp('date');
    return value.a.slice(0,5);
}

提供されたものと同様のテンプレート ドキュメントを使用して、mapReduce コマンドを呼び出してこれを実行します。

> db.top5.mapReduce(map, reduce, {finalize:final, out:{inline:1}})
{
    "results" : [
        {
            "_id" : "group1",
            "value" : [
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe13"),
                    "name" : "group1",
                    "date" : ISODate("2013-04-17T20:07:59.498Z"),
                    "contents" : 0.23778377776034176
                },
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe0e"),
                    "name" : "group1",
                    "date" : ISODate("2013-04-17T20:07:59.467Z"),
                    "contents" : 0.4434165076818317
                },
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe09"),
                    "name" : "group1",
                    "date" : ISODate("2013-04-17T20:07:59.436Z"),
                    "contents" : 0.5935856597498059
                },
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe04"),
                    "name" : "group1",
                    "date" : ISODate("2013-04-17T20:07:59.405Z"),
                    "contents" : 0.3912118375301361
                },
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfdff"),
                    "name" : "group1",
                    "date" : ISODate("2013-04-17T20:07:59.372Z"),
                    "contents" : 0.221651989268139
                }
            ]
        },
        {
            "_id" : "group2",
            "value" : [
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe14"),
                    "name" : "group2",
                    "date" : ISODate("2013-04-17T20:07:59.504Z"),
                    "contents" : 0.019611883210018277
                },
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe0f"),
                    "name" : "group2",
                    "date" : ISODate("2013-04-17T20:07:59.473Z"),
                    "contents" : 0.5670706110540777
                },
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe0a"),
                    "name" : "group2",
                    "date" : ISODate("2013-04-17T20:07:59.442Z"),
                    "contents" : 0.893193120136857
                },
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe05"),
                    "name" : "group2",
                    "date" : ISODate("2013-04-17T20:07:59.411Z"),
                    "contents" : 0.9496864483226091
                },
                {
                    "_id" : ObjectId("516f011fbfd3e39f184cfe00"),
                    "name" : "group2",
                    "date" : ISODate("2013-04-17T20:07:59.378Z"),
                    "contents" : 0.013748752186074853
                }
            ]
        },
        {
            "_id" : "group3",
                        ...
                }
            ]
        }
    ],
    "timeMillis" : 15,
    "counts" : {
        "input" : 80,
        "emit" : 80,
        "reduce" : 5,
        "output" : 5
    },
    "ok" : 1,
}

各結果には、グループ名としての _id と、そのグループ名のコレクションからの最新の 5 つのドキュメントの配列としての値があります。

于 2013-04-17T20:42:46.400 に答える
-1

$limit ステージにパイプされた集約フレームワーク $group ステージが必要です... 何らかの方法でレコードを $sort することも必要です。そうしないと、制限の動作が未定義になり、返されるドキュメントは疑似ランダムになります (内部で使用される順序モンゴ)

そのようなもの: db.collection.aggregate([{$group:...},{$sort:...},{$limit:...}])

詳細を知りたい場合は、ここにドキュメントがあります

于 2013-04-17T18:26:00.497 に答える