我在使用MongoDB聚合框架计算数据库中的事件类型时遇到了一些麻烦。如何计算value.count
字段的每个唯一第三个索引的_id.val
字段的总和?
我的数据的基本结构如下:
{ _id: { evt: "click", val: [ "default", "125", "311", "1" ] }, value: { count: 1 } }
{ _id: { evt: "click", val: [ "default", "154", "321", "2" ] }, value: { count: 2 } }
{ _id: { evt: "click", val: [ "default", "192", "263", "1" ] }, value: { count: 4 } }
val
字段中的值分别表示["type","x","y","time"]
。
我试图提取time
密钥的第三个索引或_id.val
值。输出我希望实现:
1: 5
2: 2
我一直试图通过这个PHP来做到这一点:
$ops2 = array(
array(
'$match' => $q2
),
array(
'$group' => array(
'_id' => array(
'evt' => '$_id.evt',
'time' => '$_id.val.3'
),
'count' => array('$sum' => '$value.count' )
)
)
);
但它似乎不喜欢组数组中的3
索引
答案 0 :(得分:1)
起初,我认为你对Mongo的理解可能有些不对......因为mongo中的每个文档都应该有其独特的_id,以便从别人那里识别出来。所以我为每个对象添加了一个_id,并改变了你的起源" _id"字段到"数据"。现在的结构是:
/* 1 */
{
"_id" : "ubLrDptWvJE7LZqDF",
"data" : {
"evt" : "click",
"val" : [ "default", "125", "311", "1" ]
},
"value" : {
"count" : 1
}
}
/* 2 */
{
"_id" : "C2QCEhvCsp3xG6EKZ",
"data" : {
"evt" : "click",
"val" : [ "default", "154", "321", "2" ]
},
"value" : {
"count" : 2
}
}
/* 3 */
{
"_id" : "bT72z7gMKoyX5JfHL",
"data" : {
"evt" : "click",
"val" : [ "default", "192", "263", "1" ]
},
"value" : {
"count" : 4
}
}
我不知道如何在PHP中执行此查询,因为我只知道一点PHP ......但我可以举例说明在Javascript中使用聚合,其代码和输出如下:
以下是一些有用的链接:using mongo in PHP 我希望它可以帮助你完美地解决你的问题: - )
答案 1 :(得分:1)
您正在使用的数据看起来已经成为mapReduce操作的输出,因为它具有特定的" _id"和"价值" mapReduce prodcues的结构。因此,您可能最好回到实现该流程的逻辑,并遵循相同的原则来提取和总计您想要的内容,或者至少将其输出形式更改为:
{
_id: {
evt: "click",
val: { "type": "default", "x": "125", "y": "311", "time": "1" }
},
value: { count: 1 }
},
{
_id: {
evt: "click",
val: { "type": "default", "x": "154", "y": "321", "time": "2" }
},
value: { count: 2 }
},
{
_id: {
evt: "click",
val: { "type": "default", "x": "192", "y": "263", "time": "1" }
},
value: { count: 4 }
}
问题在于聚合框架"目前"缺乏解决"索引"数组的位置(真实"非关联"数组而不是PHP数组),并且在您尝试这样做时将始终返回null
。
缺乏返回原始源或mapReduce操作的能力,那么您可以对此数据编写mapReduce操作以获得预期的结果(shell表示,因为它无论如何都将成为JavaScript):< / p>
db.collection.mapReduce(
function() {
emit({ evt: this._id.evt, time: this._id.val[3] }, this.value.count)
},
function(key,values) {
return Array.sum(values)
},
{ out: { inline: 1 } }
)
返回典型的mapReduce输出,如下所示:
{
"_id" : {
"evt" : "click",
"time" : "1"
},
"value" : 5
},
{
"_id" : {
"evt" : "click",
"time" : "2"
},
"value" : 2
}
如果您至少能够将当前输出集合转换为上面第一个建议的表单,那么您将使用这样的聚合框架(再次通用代表)运行:
{ "$group": {
"_id": {
"evt": "$_id.evt",
"time": "$_id.val.time"
},
"count": { "$sum": "$value.count" }
}}
当然会从改变后的数据中得出结论:
{ "_id" : { "evt" : "click", "time" : "2" }, "count" : 2 }
{ "_id" : { "evt" : "click", "time" : "1" }, "count" : 5 }
在MongoDB的未来版本中,将有一个允许数组处理的$slice
运算符,因此使用您当前的结构可以改为:
{ "$group": {
"_id": {
"evt": "$_id.evt",
"time": { "$slice": [ "$_id.val", 3,1 ] }
},
"count": { "$sum": "$value.count" }
}}
允许挑选第三个&#34;数组中的索引元素,虽然这当然会返回一个&#34;数组&#34;像这样的元素:
{ "_id" : { "evt" : "click", "time" : [ "2" ] }, "count" : 2 }
{ "_id" : { "evt" : "click", "time" : [ "1" ] }, "count" : 5 }
所以现在,如果你可以改变你的初始mapReduce输出,那就去做吧。要么是这里显示的形式,要么只是修改初始查询以获得您想要的最终结果。修改推荐的表单将至少允许.aggregate()
命令工作,如此处的第二个示例所示。
如果没有,那么mapReduce仍然是目前写作的唯一方式,如&#34; first&#34;示例