【问题标题】:MongoDB aggregate sub-array as group _idMongoDB 将子数组聚合为组 _id
【发布时间】:2015-11-16 00:21:49
【问题描述】:

我在使用 MongoDB 聚合框架计算数据库中的事件类型时遇到了一些问题。如何计算 value.count 字段的每个唯一第三个索引的 value.count 字段的总和?

我的数据的基本结构如下:

{ _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 索引

【问题讨论】:

    标签: php mongodb mongodb-query aggregation-framework


    【解决方案1】:

    您正在处理的数据看起来已经作为 mapReduce 操作的输出,因为它具有 mapReduce 产生的特定“_id”和“value”结构。因此,您最好回到如何实现该过程的逻辑并遵循相同的方法来提取和汇总您想要的内容,或者至少将其输出形式更改为:

    { 
        _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):

    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" }
        }}
    

    这允许从数组中选择“第三个”索引元素,尽管这当然仍会返回一个“数组”作为元素,如下所示:

    { "_id" : { "evt" : "click", "time" : [ "2" ] }, "count" : 2 }
    { "_id" : { "evt" : "click", "time" : [ "1" ] }, "count" : 5 }
    

    所以现在,如果你可以改变你的初始 mapReduce 输出,那就去做吧。可以使用此处显示的表单,也可以仅使用对初始查询的修改来获得您想要的最终结果。修改为推荐的形式至少可以让.aggregate() 命令像这里的第二个示例中所示的那样工作。

    如果不是,那么mapReduce仍然是目前唯一的写法,如“第一个”例子所示。

    【讨论】:

      【解决方案2】:

      一开始,我觉得你对 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 我希望它可以帮助您完美地解决您的问题:-)

      【讨论】:

        猜你喜欢
        • 2015-03-28
        • 2016-08-16
        • 2023-03-21
        • 2021-10-18
        • 1970-01-01
        • 2019-05-10
        • 2021-01-25
        • 2014-12-01
        • 1970-01-01
        相关资源
        最近更新 更多