1

このように place_id と user_id を含む場所への訪問ユーザーのデータベースがあります

{place_id : 1, user_id : 1}
{place_id : 1, user_id : 1}
{place_id : 1, user_id : 2}
{place_id : 2, user_id : 3}
{place_id : 2, user_id : 3}

そして、それぞれの場所で異なるユーザー数を取得したいと考えています。最終的に、次のネイティブ mongo アグリゲーションになりました。

db.collection.aggregate([{
        $group: {
            _id: "$place_id",
            setOfUsers: {
                $addToSet: "$user_id"
            }
        }
    }, {
        $project: {
            distinctUserCount: {
                $size: "$setOfUsers"
            }
        }
    }])

そして今、私はSpring Dataを使用してそれを実装したいと思っています.SpringデータAPIにはそのようなものがないため、少なくとも私はそれを参照していません.

    GroupOperation group = Aggregation.group("place_id").addToSet("user_id").as("setOfUsers");
    ProjectionOperation project = Aggregation.project(). .... ?

ネストされた API を使用できるよりも、サイズ フィールドを作成する方法もあるかもしれません。

Aggregation.project().and("distinctUserCount").nested( ???);

どんな助けでも大歓迎です。

4

1 に答える 1

3

私はこれに「ワンヒット」で答えるつもりなので、「$project」の問題に対処するのではなく、より良いアプローチがあることをここでアドバイスします。

オペレーターは、追加する要素の$addToSet「一意の」配列 (または「セット」) を作成します。ただし、基本的に$groupはそれ自体が別の形式であり、要素が結果の「配列」(または「セット」) に追加されるという違いがあります。

これはスケーラビリティにとって「悪い」ことです。ここでの潜在的な問題は、「セット」が実際にドキュメント サイズの BSON 制限を超えていることです。今はそうではないかもしれませんが、あなたが今書いているコードが 10 年後に何をしているのか誰にもわかりません。

したがって、$group実際には同じことであり、「個別の」カウントを取得するには「2」のパイプラインステージが必要であり、$group代わりに「2」のステージが必要です。

    Aggregation pipeline = newAggregation(
        group(fields("place_id","user_id")),
        group("_id.place_id").count().as("distinctUserCount")
    );

以下と同等のシェルであること:

[
    { "$group": {
        "_id": { "place_id": "$place_id", "user_id": "$user_id" }
    }},
    { "$group": {
        "_id": "$_id.place_id",
        "distinctUserCount": { "$sum": 1 }
    }}
]

これは単純なコードであり、個々の「user_id」値が最初はパイプライン内の個別のドキュメントに含まれているため、はるかに「スケーラブル」です。したがって、「2 番目」$group( $project の $size の代わり) は、最初のグループ化キーですでに決定されている個別の金額を「カウント」します。

制限と落とし穴を学び、適切にコーディングしてください。

于 2015-07-24T11:15:18.117 に答える