想象一下,我有一个包含以下文档的MonogDB集合:
{name: 'Some Name', components: {ARRAY OF ITEMS}}
如何返回组件中的名称和项目数? 我是否必须使用map / reduce?
我正在使用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 :(得分: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);
最后,我强烈建议,如果您尝试定期访问组件的计数,则将计数存储为文档的附加属性,并在其发生更改时进行更新。如果您尝试编写基于此计数进行过滤的查询,那么您还可以在该组件属性上添加索引。
答案 1 :(得分:0)
吉姆 -
这是两个独立的行动;除非你想利用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']);
}
答案 2 :(得分:0)
您可以使用db.eval()并使用JavaScript编写计算。
答案 3 :(得分: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/
我遇到的问题是mongo将字段放入"$field"
并且PHP完全不喜欢它,因为它进行变量插值的方式。但是,一旦你逃离$
,它就可以正常工作。
我认为对于这种特殊情况,你需要做类似的事情,但使用$project
代替$group
这样
$collection = (new Client())->db->my_collection;
$collection->aggregate([
'$match' => ['name' => 'Some Name'],
'$project' => [
'name' => "\$name",
'total'=> ['$sum' => "\$components"]
]
]);
这是一个古老的问题,但是因为没有回答,我会把它留在这里。