MongoDB MapReduce——是否有聚合替代方案?



我有一个使用模式的文档集合,像这样(一些成员编校):

{
    "_id" : ObjectId("539f41a95d1887b57ab78bea"),
    "answers" : {
        "ratings" : {
            "positivity" : [ 
                2, 
                3, 
                5
            ],
            "activity" : [ 
                4, 
                4, 
                3
            ],
    },
    "media" : [ 
        ObjectId("537ea185df872bb71e4df270"), 
        ObjectId("537ea185df872bb71e4df275"), 
        ObjectId("537ea185df872bb71e4df272")
    ]
}

在此模式中,第一、第二和第三个positivity评级分别对应于media数组中的第一、第二和第三个条目。activity评级也是如此。我需要计算关于集合中所有文档中相关media对象的positivityactivity评级的统计信息。现在,我正在用MapReduce做这个。然而,我想用聚合管道来完成这个任务。

理想情况下,我希望同时对mediaanswers.ratings.positivityanswers.ratings.activity数组进行$unwind处理,这样我就可以根据前面的示例得到以下三个文档:

[
    {
        "_id" : ObjectId("539f41a95d1887b57ab78bea"),
        "answers" : {
            "ratings" : {
                "positivity" : 2,
                "activity" : 4
            }
        },
        "media" : ObjectId("537ea185df872bb71e4df270")
    },
    {
        "_id" : ObjectId("539f41a95d1887b57ab78bea"),
        "answers" : {
            "ratings" : {
                "positivity" : 3
                "activity" : 4
            }
        },
        "media" : ObjectId("537ea185df872bb71e4df275")
    },
    {
        "_id" : ObjectId("539f41a95d1887b57ab78bea"),
        "answers" : {
            "ratings" : {
                "positivity" : 5
                "activity" : 3
            }
        },
        "media" : ObjectId("537ea185df872bb71e4df272")
    }
]

有办法做到这一点吗?

当前的聚合框架不允许您这样做。能够展开已知大小相同的多个数组并为每个数组的第i个值创建文档将是一个很好的特性。

如果你想使用聚合框架,你需要稍微改变一下你的模式。以以下文档模式为例:

{
    "_id" : ObjectId("539f41a95d1887b57ab78bea"),
    "answers" : {
        "ratings" : {
            "positivity" : [ 
                {k:1, v:2}, 
                {k:2, v:3}, 
                {k:3, v:5}
            ],
            "activity" : [ 
                {k:1, v:4}, 
                {k:2, v:4}, 
                {k:3, v:3}
            ],
    }},
    "media" : [ 
        {k:1, v:ObjectId("537ea185df872bb71e4df270")}, 
        {k:2, v:ObjectId("537ea185df872bb71e4df275")}, 
        {k:3, v:ObjectId("537ea185df872bb71e4df272")}
    ]
}

这样做实际上是在给数组内的对象添加索引。在这之后,它只是展开所有数组和匹配键的问题。

db.test.aggregate([{$unwind:"$media"},
{$unwind:"$answers.ratings.positivity"},
{$unwind:"$answers.ratings.activity"},
{$project:{"media":1, "answers.ratings.positivity":1,"answers.ratings.activity":1,
    include:{$and:[
                  {$eq:["$media.k", "$answers.ratings.positivity.k"]},
                  {$eq:["$media.k", "$answers.ratings.activity.k"]}
            ]}}
},
{$match:{include:true}}])

输出为:

[ 
        {
            "_id" : ObjectId("539f41a95d1887b57ab78bea"),
            "answers" : {
                "ratings" : {
                    "positivity" : {
                        "k" : 1,
                        "v" : 2
                    },
                    "activity" : {
                        "k" : 1,
                        "v" : 4
                    }
                }
            },
            "media" : {
                "k" : 1,
                "v" : ObjectId("537ea185df872bb71e4df270")
            },
            "include" : true
        }, 
        {
            "_id" : ObjectId("539f41a95d1887b57ab78bea"),
            "answers" : {
                "ratings" : {
                    "positivity" : {
                        "k" : 2,
                        "v" : 3
                    },
                    "activity" : {
                        "k" : 2,
                        "v" : 4
                    }
                }
            },
            "media" : {
                "k" : 2,
                "v" : ObjectId("537ea185df872bb71e4df275")
            },
            "include" : true
        }, 
        {
            "_id" : ObjectId("539f41a95d1887b57ab78bea"),
            "answers" : {
                "ratings" : {
                    "positivity" : {
                        "k" : 3,
                        "v" : 5
                    },
                    "activity" : {
                        "k" : 3,
                        "v" : 3
                    }
                }
            },
            "media" : {
                "k" : 3,
                "v" : ObjectId("537ea185df872bb71e4df272")
            },
            "include" : true
        }
    ]

这样做会产生大量额外的文档开销,并且可能比当前的MapReduce实现慢。您需要运行测试来检查这一点。为此所需的计算量将根据这三个数组的大小以三次方式增长。

相关内容

  • 没有找到相关文章