

id,replyと言うカラムを持つテーブルhogeがあります  
replyはリプライ先のidが入っていて、リプライ先がなければnullです  
以下のようなデータがあったとします。

[code]

    {
        "id":"1",
        "reply":null
    },
    {
        "id":"2",
        "reply":"1"
    },
    {
        "id":"3",
        "reply":"2"
    },
    {
        "id":"4",
        "reply":"1"
    }
    
[/code]

これを取得する時に以下のように自信に対するリプライの合計も取得するにはどうすればいいでしょうか？

[code]

    {
        "id":"1",
        "reply":null,
        "replyCount":2
    },
    {
        "id":"2",
        "reply":"1",
        "replyCount":1
    },
    {
        "id":"3",
        "reply":"2",
        "replyCount":0
    },
    {
        "id":"4",
        "reply":"1",
        "replyCount":0
    }
    
[/code]


CC BY-SA 3.0
2016-12-02T09:24:12.917
30836
2017-03-06T10:49:36.147
19765
question
mongodb
MongoDBでリプライの合計を取得したい


サンプルデータ：  
（注）MongoDBテーブルには必ず「_id」フィールドが入っていますが敢えて表示しないようになっています。質問の「id」フィールド名をそのまま使います。

[code]

    db.hoge.find()
    { "_id" : ObjectId("5841f3d27261c6e2fca154d4"), "id" : "1", "reply" : null }
    { "_id" : ObjectId("5841f3d27261c6e2fca154d5"), "id" : "2", "reply" : "1" }
    { "_id" : ObjectId("5841f3d27261c6e2fca154d6"), "id" : "3", "reply" : "2" }
    { "_id" : ObjectId("5841f3d27261c6e2fca154d7"), "id" : "4", "reply" : "1" }
    > db.hoge.find({}, {_id: false})
    { "id" : "1", "reply" : null }
    { "id" : "2", "reply" : "1" }
    { "id" : "3", "reply" : "2" }
    { "id" : "4", "reply" : "1" }
    
[/code]

基本的に以下二つの結果を合流することになります。「id」と「reply」の項目：

[code]

    > db.hoge.find({}, {_id: false, "id": true, "reply": true}).sort({"id": 1})
    { "id" : "1", "reply" : null }
    { "id" : "2", "reply" : "1" }
    { "id" : "3", "reply" : "2" }
    { "id" : "4", "reply" : "1" }
    
[/code]

さらにこの集計結果。  
（注）「_id」フィールドは集計結果のキーです。今回ご質問のサンプルデータにあるリプライ元の「id」フィールドと同じ意味です。

[code]

    > db.hoge.aggregate([
        {$group: {_id: "$reply", "replyCount": {$sum: 1}}}, 
        {$match: {"_id": {$ne: null}}}, 
        {$sort: {"_id": 1}}])
    { "_id" : "1", "replyCount" : 2 }
    { "_id" : "2", "replyCount" : 1 }
    
[/code]

つまり、方法の一つは「この２つの結果をクライント側（アプリケーション側）でマージする」です。

もう一つは$lookupの集計ステージと集計配列$sizeのオペレーターを適用してこのように出力する方法です。

[code]

    > db.hoge.aggregate([
        {$project: {"_id": false, "id": "$id", "reply": "$reply"}}, 
        {$lookup: {from: "hoge", localField: "id", foreignField: "reply", as: "replies"}}, 
        {$project: {"id": "$id", "reply": "$reply", "replyCount": {$size: "$replies"}}}] )
    { "id" : "1", "reply" : null, "replyCount" : 2 }
    { "id" : "2", "reply" : "1", "replyCount" : 1 }
    { "id" : "3", "reply" : "2", "replyCount" : 0 }
    { "id" : "4", "reply" : "1", "replyCount" : 0 }
    
[/code]


CC BY-SA 3.0
2016-12-02T23:45:22.657
30850
2016-12-02T23:45:22.657
113
30836
answer