我是地图减少概念的新手,尽管我进展缓慢,但我发现一些需要帮助的问题。
我有一个简单的集合,由id,城市和目的地组成,如下所示:
{ "_id" : "5230e7e00000000000000000", "city" : "Boston", "to" : "Chicago" },
{ "_id" : "523fe7e00000000000000000", "city" : "New York", "to" : "Miami" },
{ "_id" : "5240e1e00000000000000000", "city" : "Boston", "to" : "Miami" },
{ "_id" : "536fe4e00000000000000000", "city" : "Washington D.C.", "to" : "Boston" },
{ "_id" : "53ffe7e00000000000000000", "city" : "New York", "to" : "Boston" },
{ "_id" : "5740e1e00000000000000000", "city" : "Boston", "to" : "Miami" },
...
(请注意,此数据仅供参考)
我想按城市对目的地进行分组,包括计数:
{ "city" : "Boston", values : [{"Chicago",1}, {"Miami",2}] }
{ "city" : "New York", values : [{"Miami",1}, {"Boston",1}] }
{ "city" : "Washington D.C.", values : [{"Boston", 1}] }
为此,我开始使用这个函数来映射:
function() {
emit(this.city, this.to);
}
执行预期的分组。我的reduce函数是这样的:
function(key, values) {
var reduced = {"to":[]};
for (var i in values) {
var item = values[i];
reduced.to.push(item);
}
return reduced;
}
这给出了一些预期的输出:
{ "_id" : ObjectId("522f8a9181f01e671a853adb"), "value" : { "to" : [ "Boston", "Miami" ] } }
{ "_id" : ObjectId("522f933a81f01e671a853ade"), "value" : { "to" : [ "Chicago", "Miami", "Miami" ] } }
{ "_id" : ObjectId("5231f0ed81f01e671a853ae0"), "value" : "Boston" }
如您所见,我仍然没有计算重复的城市,但如上所示,由于某种原因,输出中的最后一个结果看起来并不好。我本来以为是
{ "_id" : ObjectId("5231f0ed81f01e671a853ae0"), "value" : { "to" : ["Boston"] } }
这与只有一个项目的事实有关吗?有什么办法可以得到这个吗?
谢谢。
我看到你在问一个PHP问题,但你正在使用javascript来问,所以我假设javascript的答案会帮助你推动事情的发展。 因此,这里是 shell 中运行聚合所需的 JavaScript。 我强烈建议你让你的聚合在shell(或其他一些javascript编辑器)中工作,然后将其翻译成你选择的语言。 使用这种方法更容易看到正在发生的事情,并且在那里更快。 然后,您可以运行:
use admin
db.runCommand( { setParameter: 1, logLevel: 2 } )
检查所选语言的 bson 输出与外壳的外观。 如果 mongo 在前台,这将出现在终端中,否则您将无法查看日志。
使用 Mongo 对聚合框架 [AF] 中的路由求和是相当困难的。 自动对焦比地图缩减更快、更容易使用[MR]。 尽管在这种情况下它们都有类似的问题,但简单地推送到数组本身不会产生计数(在 MR 中,您要么在 reduce 函数中需要更多的逻辑,要么需要使用 finalize 函数)。
使用提供的示例数据的 AF 时,此管道很有用:
db.agg1.aggregate([
{$group:{
_id: { city: "$city", to: "$to" },
count: { $sum: 1 }
}},
{$group: {
_id: "$_id.city",
to:{ $push: {to: "$_id.to", count: "$count"}}
}}
]);
聚合框架只能对已知字段进行操作,但可以对许多管道操作进行操作,因此需要考虑一个问题。上面,第一阶段计算所需的数字,其中有 3 个固定字段:源、目的地和计数。第二阶段有 2 个固定字段,其中一个是数组,它只被推送到(最终形式的所有数据都在那里)。
对于 MR,您可以执行以下操作:
var map = function() {
var key = {source:this.city, dest:this.to};
emit(key, 1);
};
var reduce = function(key, values) {
return Array.sum(values);
};
但是,必须使用单独的功能来美化它。
如果您有任何其他问题,请随时提问。
最好查理