0

我想按以下格式的数据集合中的目标进行分组。

[unique_id] => 649083802  
[objectives_compleeted_log_queue] => Array (  
)  
[objectives] => Array (      
        [37] => Array (  
            [is_completed] =>   
            [tasks] => Array (  
            [56] => Array (  
                [completed_count] => 0  
                [actions] => Array (  
                    [0] => 0  
                )  
            )  
        )  
    )  
    [96] => Array (  
        [is_completed] =>   
        [tasks] => Array (   
            [123] => Array (  
                [completed_count] => 0  
                [actions] => Array (  
                    [0] => 0  
                )  
            )  
        )  
    )  
    [97] => Array (  
        [is_completed] =>   
        [tasks] => Array (  
            [124] => Array (  
                [completed_count] => 0  
                [actions] => Array (  
                    [0] => 0  
                )  
            )  
        )  
    )

在上面的示例中,我需要对每个目标(37、96、97...)的 unique_ids 进行分组。对不起,对 mongo db 很陌生

4

1 回答 1

1

根据经验,在文档中使用动态字段名称(例如objectives.37)会降低索引和查询的灵活性。对于初学者,您将无法利用多键索引

不过,我们可以使用map/reduce来聚合和计算现有架构中的不同 ID。为了使以下示例保持简洁,我将字段名称缩短为o数据夹具中的不相关数据。

<?php

$m = new Mongo();
$db = $m->test;

$db->foo->drop();
$db->foo->insert(['o' => [36 => [], 63 => [], 64 => []]]);
$db->foo->insert(['o' => [12 => [], 36 => [], 97 => []]]);

$result = $db->command([
  'mapreduce' => 'foo',
  'map' => new MongoCode('
    function() {
      for (var key in this.o) emit(key, { count: 1 });
    }
  '),
  'reduce' => new MongoCode('
    function(key, values) {
      var r = { count: 0 };
      values.forEach(function(v) { r.count += v.count; });
      return r;
    }
  '),
  'out' => ['inline' => 1]
]);

echo json_encode($result, JSON_PRETTY_PRINT);

在这里,我们在整个集合中执行 map 函数,在o我们处理的对象中发出每个唯一键。对于每次发射,我们发射的初始值为{count: 1}。映射后,我们有一大堆由密钥和{count: 1}对组成的排放量。然后调用我们的 reduce 方法来处理不同键的这些中间结果。参数中的每个对象都values遵循相同的结构(即我们之前发出的相同值),并且我们期望返回相同结构的单个简化值。

该脚本将产生以下输出:

$ php mr.php 
{
    "results": [
        {
            "_id": "12",
            "value": {
                "count": 1
            }
        },
        {
            "_id": "36",
            "value": {
                "count": 2
            }
        },
        {
            "_id": "63",
            "value": {
                "count": 1
            }
        },
        {
            "_id": "64",
            "value": {
                "count": 1
            }
        },
        {
            "_id": "97",
            "value": {
                "count": 1
            }
        }
    ],
    "timeMillis": 17,
    "counts": {
        "input": 2,
        "emit": 6,
        "reduce": 1,
        "output": 5
    },
    "ok": 1
}

如果您改为重新设计架构,使其objectives成为嵌套对象数组,我们可以利用 MongoDB 2.2+ 中的聚合框架来更轻松地计算相同的结果:

<?php

$m = new Mongo();
$db = $m->test;

$db->foo->drop();
$db->foo->insert(['o' => [['id' => 36], ['id' => 63], ['id' => 64]]]);
$db->foo->insert(['o' => [['id' => 12], ['id' => 36], ['id' => 97]]]);

$result = $db->command([
  'aggregate' => 'foo',
  'pipeline' => [
    ['$project' => ['o' => 1]],
    ['$unwind' => '$o'],
    ['$group' => ['_id' => '$o.id', 'count' => ['$sum' => 1]]],
  ],
]);

echo json_encode($result, JSON_PRETTY_PRINT);

在这里,我们使用聚合管道依次进行三个操作:

  • 投影扫描文档的o字段,类似于在查找查询中选择特定的输出字段。
  • o展开我们遇到的每个数组。将管道视为文档流,我们将有两个文档进入此步骤,每个文档在各自的o字段中都有三个嵌套对象。展开将产生六个文档进行下一步,每个o数组字段由数组的一个元素替换。
  • 此时对流中的所有文档进行分组,使用o.id字段作为分组标识符,并使用总和作为每个元素的组值。对于每个分组的元素,count值字段将增加一。

此脚本产生输出:

$ php af.php 
{
    "result": [
        {
            "_id": 12,
            "count": 1
        },
        {
            "_id": 63,
            "count": 1
        },
        {
            "_id": 97,
            "count": 1
        },
        {
            "_id": 64,
            "count": 1
        },
        {
            "_id": 36,
            "count": 2
        }
    ],
    "ok": 1
}
于 2012-08-20T20:34:49.287 回答