如何在mongodb中引用子集合


How to reference sub collections in mongo db

我想在一个数据格式如下的集合中按目标分组。

[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_id进行分组。很抱歉对mongo db 非常陌生

根据经验,在文档中使用动态字段名(例如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
}