为MongoDB映射Reduce

时间:2013-07-29 06:59:24

标签: javascript mongodb mapreduce

我有一个集合,其中每个对象都包含用户的详细信息以及用户对特定产品的评论,如下所示

{
"_id" : ObjectId("51efcbc8786df13540e46887"),
"value": {
    "UserDetails" : [
                        [
                            {
                                "country" : "CA",
                                "gender" : "M",
                                "age" : "18",
                                "userIdtemp" : ObjectId("51efcbc8786df13540e46887")
                            }
                        ]
                    ],
    "comments" :    [
                        {
                            "commentId" : ObjectId("51efcc41786df13540e46891"),
                            "comment" : "Hey, what's up?",
                            "created" : ISODate("2013-07-24T12:44:49.400Z"),
                            "productId" : ObjectId("51efcbd4786df13540e4688c"),
                            "userId" : ObjectId("51efcbc8786df13540e46887")
                        },
                        {
                            "commentId" : ObjectId("51efcc43786df13540e46893"),
                            "comment" : "Cool",
                            "created" : ISODate("2013-07-24T12:44:51.004Z"),
                            "productId" : ObjectId("51efcbd2786df13540e4688b"),
                            "userId" : ObjectId("51efcbc8786df13540e46887")
                        }
                    ]
    }
}
{
"_id" : ObjectId("51efcbc8786df13540e46888"),
"value" : {
     "UserDetails" : [
                        [
                            {
                               "country" : "US",
                               "gender" : "M",
                               "age" : "25",
                               "userIdtemp" : ObjectId("51efcbc8786df13540e46888")
                            }
                        ]
                ],
     "comments" : [
                    {
                        "commentId" : ObjectId("51efcc41786df13540e46892"),
                        "comment" : "Not much",
                        "created" : ISODate("2013-07-24T12:44:49.475Z"),
                        "productId" : ObjectId("51efcbd4786df13540e4688c"),
                        "userId" : ObjectId("51efcbc8786df13540e46888")
                    }
                ]
}
}
{
    "_id" : ObjectId("51efcbc8786df13540e46889"),
    "value" : {
            "UserDetails" : [
                    {
                            "country" : "US",
                            "gender" : "F",
                            "age" : "13",
                            "userIdtemp" : ObjectId("51efcbc8786df13540e46889")
                    }
            ]
    }
}

我必须单独提取注释以​​及带有key作为productId的userDetails,所以我写了类似下面的地图

mapCommentsFrom = function(){
if("comments" in this.value)
{
    for(var idx = 0;idx<this.value.comments.length;idx++){
        var key = this.value.comments[idx].productId;
        var value = [{
            commentId: this.value.comments[idx].commentId,
            comment:this.value.comments[idx].comment,
            created:this.value.comments[idx].created,
            productId:this.value.comments[idx].productId,
            userId:this.value.comments[idx].userId,
            country:this.value.UserDetails[0][0].country,
            gender:this.value.UserDetails[0][0].gender,
            age : this.value.UserDetails[0][0].age
        }]

    }
}
emit(key,value);
}

reduceFrom = function(k,values){
return values;
}

但是哪里的评论数量多于一个,我只得到最后一条评论以及用户详细信息和其他密钥以及值即将为空。像这样的东西

{ "_id" : null, "value" : null }
{
    "_id" : ObjectId("51efcbd2786df13540e4688b"),
    "value" : [
            {
                    "length" : 2,
                    "commentId" : ObjectId("51efcc43786df13540e46893"),
                    "comment" : "Cool",
                    "created" : ISODate("2013-07-24T12:44:51.004Z"),
                    "productId" : ObjectId("51efcbd2786df13540e4688b"),
                    "userId" : ObjectId("51efcbc8786df13540e46887"),
                    "country" : "CA",
                    "gender" : "M",
                    "age" : "18"
            }
    ]
}
{
    "_id" : ObjectId("51efcbd4786df13540e4688c"),
    "value" : [
            {
                    "length" : 1,
                    "commentId" : ObjectId("51efcc41786df13540e46892"),
                    "comment" : "Not much",
                    "created" : ISODate("2013-07-24T12:44:49.475Z"),
                    "productId" : ObjectId("51efcbd4786df13540e4688c"),
                    "userId" : ObjectId("51efcbc8786df13540e46888"),
                    "country" : "US",
                    "gender" : "M",
                    "age" : "25"
            }
    ]
}

有人可以帮我解释一下我错过了什么吗?

提前感谢您的帮助

3 个答案:

答案 0 :(得分:0)

由于声誉,我无法添加评论。但是你考虑过使用聚合框架吗?

$unwind运算符将非常容易地返回一个子文档数组,它比使用map / reduce更快。

我不确定它会完全按照您的要求行事,但可能有所帮助。

看看http://docs.mongodb.org/manual/reference/aggregation/unwind/

答案 1 :(得分:0)

通过,最简单的方法就是使用聚合框架。聚合框架允许您对数据执行运算符,$match用于执行查询(如find())和其他各种操作。有关详细信息,请参阅:http://docs.mongodb.org/manual/core/aggregation/

聚合框架还有一个$unwind函数,可以完全按照您的要求执行。你使用它像:

db.collection.aggregate( [
    { $unwind: '$value.comments' },
    { $project: {
        _id: '$value.comments.productId',
        value: 1
    } }
] );

在您的示例文档中,返回:

{
    "result" : [
        {
            "_id" : ObjectId("51efcbd4786df13540e4688c"),
            "value" : {
                "UserDetails" : [
                    [
                        {
                            "country" : "CA",
                            "gender" : "M",
                            "age" : "18",
                            "userIdtemp" : ObjectId("51efcbc8786df13540e46887")
                        }
                    ]
                ],
                "comments" : {
                    "commentId" : ObjectId("51efcc41786df13540e46891"),
                    "comment" : "Hey, what's up?",
                    "created" : ISODate("2013-07-24T12:44:49.400Z"),
                    "productId" : ObjectId("51efcbd4786df13540e4688c"),
                    "userId" : ObjectId("51efcbc8786df13540e46887")
                }
            }
        },
        {
            "_id" : ObjectId("51efcbd2786df13540e4688b"),
            "value" : {
                "UserDetails" : [
                    [
                        {
                            "country" : "CA",
                            "gender" : "M",
                            "age" : "18",
                            "userIdtemp" : ObjectId("51efcbc8786df13540e46887")
                        }
                    ]
                ],
                "comments" : {
                    "commentId" : ObjectId("51efcc43786df13540e46893"),
                    "comment" : "Cool",
                    "created" : ISODate("2013-07-24T12:44:51.004Z"),
                    "productId" : ObjectId("51efcbd2786df13540e4688b"),
                    "userId" : ObjectId("51efcbc8786df13540e46887")
                }
            }
        },
        {
            "_id" : ObjectId("51efcbd4786df13540e4688c"),
            "value" : {
                "UserDetails" : [
                    [
                        {
                            "country" : "US",
                            "gender" : "M",
                            "age" : "25",
                            "userIdtemp" : ObjectId("51efcbc8786df13540e46888")
                        }
                    ]
                ],
                "comments" : {
                    "commentId" : ObjectId("51efcc41786df13540e46892"),
                    "comment" : "Not much",
                    "created" : ISODate("2013-07-24T12:44:49.475Z"),
                    "productId" : ObjectId("51efcbd4786df13540e4688c"),
                    "userId" : ObjectId("51efcbc8786df13540e46888")
                }
            }
        }
    ],
    "ok" : 1
}

答案 2 :(得分:0)

因为你没有在map函数中发出它们。 在for循环中移动emit函数。

mapCommentsFrom = function(){
if("comments" in this.value){
for(var idx = 0;idx<this.value.comments.length;idx++){
    var key = this.value.comments[idx].productId;
    var value = {
        commentId: this.value.comments[idx].commentId,
        comment:this.value.comments[idx].comment,
        created:this.value.comments[idx].created,
        productId:this.value.comments[idx].productId,
        userId:this.value.comments[idx].userId,
        country:this.value.UserDetails[0][0].country,
        gender:this.value.UserDetails[0][0].gender,
        age : this.value.UserDetails[0][0].age
    }
    emit(key,value);
}
}
}

然后你可能还需要将reduce函数重写为这样的

reduceFrom = function(k,valueArray){
var returnData = { values : [] } ;
for(var i=0;i<valueArray.length;i++)
    returnData.values.push(valueArray[i]);
return returnData;

}

相关问题