Выберите * группу в агрегировании монго

Я пытаюсь сделать что-то, что, по-моему, довольно просто. Предположим, у меня есть серия записей в монго, которые имеют общий ключ и переменное количество атрибутов. Я хочу выбрать все атрибуты и группу по имени в записях. Например

{ 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" },
    }}
)