web-dev-qa-db-ja.com

配列値の合計を使用したMongoDB集約

次のデータを含むコレクションがあります。

{
    "_id" : ObjectId("5516d416d0c2323619ddbca8"),
    "date" : "28/02/2015",
    "driver" : "user1",
    "passengers" : [
        {
            "user" : "user2",
            "times" : 2
        },
        {
            "user" : "user3",
            "times" : 3
        }
    ]
}
{
    "_id" : ObjectId("5516d517d0c2323619ddbca9"),
    "date" : "27/02/2015",
    "driver" : "user2",
    "passengers" : [
        {
            "user" : "user1",
            "times" : 2
        },
        {
            "user" : "user3",
            "times" : 2
        }
    ]
}

そして、特定の乗客について、特定のドライバーと一緒にいた時間を知るために、集計を実行したいと思います。私の例では、次のようになります。foruser1:[{ driver: user2, times: 2}] user2の場合:[{ driver: user1, times: 2}] user3の場合:[{ driver: user1, times: 3}, {driver: user2, times:2}]

私はmongoにまったく慣れておらず、sumを使用して簡単な集計を実行する方法を知っていますが、配列内にある場合や、サブジェクト自体が配列内にある場合はそうではありません。この種の集計を実行する適切な方法は何ですか?より具体的には、express.jsベースのサーバーでどのように実行しますか?

8
buddy123

集約フレームワークでニーズを達成するために、最初のパイプラインステージは、ドキュメントを乗客のユーザーと照合する、問題の乗客に対する $match 操作です。配列の後に $unwind 操作が続きます。この操作は、前の操作の入力ドキュメントから乗客配列を分解して、各要素のドキュメントを出力します。分解された配列に対する別の$match操作が続き、前のドキュメントストリームをさらにフィルタリングして、一致するドキュメントのみが変更されずに次のパイプラインステージに渡されるようにします。これにより、必要なフィールドが-で投影されます。 $project 演算子。したがって、基本的にuser3の集約パイプラインは次のようになります。

db.collection.aggregate([
     {
        "$match": {
            "passengers.user": "user3"
        }
     },
     {
         "$unwind": "$passengers"
     },
     {
        "$match": {
            "passengers.user": "user3"
        }
     },
     {
         "$project": {
             "_id": 0,
            "driver": "$driver",
            "times": "$passengers.times"
        }
     }
])

結果

/* 0 */
{
    "result" : [ 
        {
            "driver" : "user1",
            "times" : 3
        }, 
        {
            "driver" : "user2",
            "times" : 2
        }
    ],
    "ok" : 1
}

[〜#〜]更新[〜#〜]

日付の異なるドライバーで重複をグループ化する場合は、前述のように、最後の直前に $group 操作を実行できます$project$sum演算子を使用して総乗客時間を計算するパイプラインステージ:

db.collection.aggregate([
     {
        "$match": {
            "passengers.user": "user3"
        }
     },
     {
         "$unwind": "$passengers"
     },
     {
        "$match": {
            "passengers.user": "user3"
        }
     },
     {
         "$group": {
             "_id": "$driver", 
             "total": {
                 "$sum": "$passengers.times"
             }
         }
     },
     {
         "$project": {
            "_id": 0,
            "driver": "$_id",
            "total": 1
        }
     }
])

結果

/* 0 */
{
    "result" : [ 
        {
            "total" : 2,
            "driver" : "user2"
        }, 
        {
            "total" : 3,
            "driver" : "user1"
        }
    ],
    "ok" : 1
}
15
chridam