2011-09-13 41 views
2

想象我有一个包含文件如下:a MonogDB集合:的MongoDB和PHP - 返回嵌套数组的计数

{name: 'Some Name', components: {ARRAY OF ITEMS}} 

我怎样才能返回名称和成分项的个数? 我必须使用地图/缩小吗?

我正在使用PHP的Mongo扩展。

编辑:在PHP的当前代码段(工作),但我只想组件的数量

$fields = array(
    'name', 'components' 
); 
$cursor = $this->collection->find(array(), $fields); 
$cursor->sort(array('created_ts' => -1)); 

if (empty($cursor) == true) { 
    return array(); 
} else { 
    return iterator_to_array($cursor); 
} 

感谢, 吉姆

+0

请提供样本(查询的预期结果)。 –

+0

阅读问题的第二部分;删除了我的答案。 – Petrogad

+0

示例结果将如{name:'项目名称',组件:3} – JimBlizz

回答

0

Jim-

这是两个独立的操作;除非你想利用这些结果PHP的计数你,你会那么做这样的事情:

$m = new Mongo(); 
$db = $m->selectDB('yourDB'); 
$collection = $db->selectCollection('MyCollection'); 
$cursor = $collection->find(array(), array("name"=>1, "components"=>1)); 
foreach($cursor as $key){ 
    echo($key['name'].' components: '.count($key['components']); 
} 
+0

羞愧,我希望避免在PHP中或作为一个单独的“行动”。尽管我猜测这不是世界末日! – JimBlizz

0

你可以使用db.eval()和JavaScript编写的计算。

+0

只是好奇,这是如何影响大规模的表现? – Petrogad

1

您可以使用map-reduce或者您可以使用简单的group查询,如下所示。由于我假设你的名字属性是一个独特的关键,这甚至应该工作,但它不是一个原因,你通常使用组函数:

db.test.group({ 
key: { name:true }, 
reduce: function(obj,prev) { 
    var count = 0; 
    for(k in obj.components) 
    count++; 
    prev.count = count; 
}, 
initial: { count: 0} 
}); 

你提到你有分量的数组,但看起来您将组件存储为对象{}而非数组[]。这就是为什么我必须在reduce函数中添加循环,以计算组件对象的所有属性。如果它实际上是一个数组,那么你可以简单地使用.length属性。

在PHP它看起来像这样(从Manual):

$keys = array('name' => 1); 
$initial = array('count' => 0); 
$reduce =<<<JS 
function(obj,prev) { 
    var count = 0; 
    for(k in obj.components) 
    count++; 
    prev.count = count; 
}, 
JS; 

$m = new Mongo(); 
$db = $m->selectDB('Database'); 
$coll = $db->selectCollection('Collection'); 
$data = $coll->group($keys, $initial, $reduce); 

最后,我强烈建议,如果你正在试图访问你存储定期的部件的数量计数作为文档的附加属性,并随时更新。如果您正在尝试编写基于此计数的筛选查询,那么您还可以在该组件属性上添加索引。

+0

PPrice;只是好奇,这是如何影响大集合的性能?感谢这篇文章,我发现它很有帮助。 – Petrogad

+1

性能将以NxM率降级,其中N是组件子文档中的平均属性数量,M是表中文档的总数。我强烈建议你为每个文档添加一个count属性,以便不必在文件上计算它 - 特别是如果使用count来过滤查询结果(索引count属性)。 – PPrice

0

今天这个跑过,如果您使用新的驱动程序与骨料,你可以做到这一点在PHP中,(鉴于此架构)

{name: 'Some Name', components: {ARRAY OF ITEMS}} 

在PHP:

$collection = (new Client())->db->my_collection; 
    $collection->aggregate([ 
     '$match' => ['name' => 'Some Name'], 
     '$group' => [ 
      '_id' => null, 
      'total'=> ['$sum' => "\$components"] 
     ] 
    ]); 

在这里招用PHP是为了逃避$美元符号,这基本上是mongo文档在使用大小或金额时所说的东西

https://docs.mongodb.com/manual/reference/operator/aggregation/size/

https://docs.mongodb.com/manual/reference/operator/aggregation/sum/

我的问题是蒙戈把字段为"$field"和PHP不一样,在所有的,因为它确实变量插值的方式。但是,一旦你逃过$,它工作正常。

我觉得对于这个特殊的情况下,你需要做同样的事情,但与$project代替$group像这样

$collection = (new Client())->db->my_collection; 
    $collection->aggregate([ 
     '$match' => ['name' => 'Some Name'], 
     '$project' => [ 
      'name' => "\$name", 
      'total'=> ['$sum' => "\$components"] 
     ] 
    ]); 

这是一个老问题,但看到没有答案挑,我会只是把这个留在这里。