Выберите * группу в агрегировании монго
Я пытаюсь сделать что-то, что, по-моему, довольно просто. Предположим, у меня есть серия записей в монго, которые имеют общий ключ и переменное количество атрибутов. Я хочу выбрать все атрибуты и группу по имени в записях. Например
{ Name: George, x: 5, y: 3 }
{ Name: George, z: 9 }
{ Name: Rob, x: 12, y: 2 }
Я хотел бы создать CSV, который выглядит так:
Name X Y Z
George 5 3 9
Rob 12 2
Пробовал
DB.data.aggregate({ $group : { _id : "$Name" } })
К сожалению, я возвращаю все имена в качестве записей, но не объединение всех возможных атрибутов.
Ответы
Ответ 1
Если вы хотите объединить атрибуты, вам нужно добавить их в group
. Например, используя $addToSet
, чтобы найти уникальные значения атрибутов x, y, z, сгруппированных по каждому имени:
db.data.aggregate(
{ $group : {
_id : "$Name",
x: { $addToSet: "$x" },
y: { $addToSet: "$y" },
z: { $addToSet: "$z" },
}}
)
Возврат:
{
"result" : [
{
"_id" : "Rob",
"x" : [
12
],
"y" : [
2
],
"z" : [ ]
},
{
"_id" : "George",
"x" : [
5
],
"y" : [
3
],
"z" : [
9
]
}
],
"ok" : 1
}
Ответ 2
Вот еще один способ сделать это:
$connection = 'mongodb://localhost:27017';
$con = new Mongo($connection); // mongo connection
$db = $con->test; /// database
$collection = $db->prb; // table
$keys = array("Name" => 1,"x"=>1,"y"=>1,"z"=>1);
// set intial values
$initial = array("count" => 0);
// JavaScript function to perform
$reduce = "function (obj, prev) { prev.count++; }";
$g = $collection->group($keys, $initial, $reduce);
echo "<pre>";
print_r($g);
Вы получите ответ примерно так: не точный вывод):
Array
(
[retval] => Array
(
[0] => Array
(
[Name] => George
[x] =>
[y] =>
[z] =>
[count] => 2
)
[1] => Array
(
[Name] => Rob
[x] =>
[y] =>
[z] =>
[count] => 1
)
)
[count] => 5
[keys] => 3
[ok] => 1
)
Ответ 3
Решение Stennie требует, чтобы вы точно знали, какие атрибуты вы хотите вернуть из каждого соответствующего элемента в запрошенной вами коллекции. Это не всегда так.
Нам пришлось решить эту проблему в Groovy приложении Grails, которое мы пишем.
Мы писали метод, подобный этому, для обработки запросов "find by X":
private List<DBObject> findDistinctPages(Map by) {
def command =
new GroupCommand(
(DBCollection) db.pages,
new BasicDBObject(['url': 1]),
new BasicDBObject(by),
new BasicDBObject([:]),
'function ( current, result ) { for(i in current) { result[i] = current[i] } }',
''
)
db.pages.group(command).sort { it.title }
}
И затем назовите его в нашем коде следующим образом:
def pages = findDistinctPages([$or: [[type: 'channel'], [type: 'main']]])
Это работает, передавая результаты исходного запроса функции javascript в конце GroupCommand. Mongo возвращает только те атрибуты, которые вы указали в исходном запросе, и ничего больше, поэтому вам нужно повторить эти результаты во второй раз, заполнив их остальными данными из mongo.
Ответ 4
используйте $addToSet
для группы, он будет работать
db.data.aggregate(
{ $group : {
_id : "$Name",
x: { $addToSet: "$x" },
y: { $addToSet: "$y" },
z: { $addToSet: "$z" },
}}
)