Всем. В групповом запросе mongo результат показывает только ключ (и) в аргументах. Как сохранить первый документ в каждой группе, например, в группе запросов mysql. например:
-------------------------------------------------------------------------
| name | age | sex | province | city | area | address |
-------------------------------------------------------------------------
| ddl1st | 22 | 纯爷们 | BeiJing | BeiJing | ChaoYang | QingNianLu |
| ddl1st | 24 | 纯爷们 | BeiJing | BeiJing | XuHui | ZhaoJiaBangLu |
| 24k | 220 | ... | .... | ... | ... | ... |
-------------------------------------------------------------------------
db.users.group({key: { name: 1},reduce: function ( curr, result ) { result.count ++ },initial: {count : 0 } })
результат:
[
{
"name" : "ddl1st",
"count" : 1
},
{
"name" : "24k",
"count" : 1
}
]
Как получить следующее:
[
{
"name" : "ddl1st",
"age" : 22,
"sex" : "纯爷们",
"province" : "BeiJing",
"city" : "BeiJing",
"area" : "ChaoYang",
"address" : "QingNianLu",
"count" : 1
},
{
"name" : "24k",
"age" : 220,
"sex" : "...",
"province" : "...",
"city" : "...",
"area" : "...",
"address" : "...",
"count" : 1
}
]
{$first: '$age'}
и тд? Возможно ли просто иметьage: $age
?$group
_id, вы можете$sort
предварительно с желаемым полем, а затем сгруппировать и использовать операторы$first
or$last
в любом поле. При накоплении идея включать другие поля (которые накапливаются / направляются / сокращаются) не имеет большого смысла даже теоретически. Однако предварительная сортировка на самом деле неэффективна по сравнению с сортировкой каждой группы внутри себя, поскольку алгоритмы сортировки сложнее, чем O (n). Я бы хотел, чтобы в MongoDB были лучшие способы.Кстати, если вы хотите сохранить не только первый документ, вы можете использовать $ addToSet Например:
db.test.aggregate({ $group: { _id: '$name', name : { $addToSet: '$name' } age : { $addToSet: '$age' }, count: { $sum: 1 } } }
источник
[отредактировано, чтобы включить предложения комментариев]
Я пришел сюда в поисках ответа, но не был доволен выбранным ответом (особенно учитывая его возраст). Я нашел этот ответ, который является лучшим решением (адаптированным):
db.test.aggregate({ $group: { _id: '$name', person: { "$first": "$$ROOT" }, count: { $sum: 1 } }, { "$replaceRoot": { "newRoot": { "$mergeObjects": ["$person", { count: "$count" }]} } } }
источник
count
поле. Вам нужно использовать,$mergeObjects
чтобы сохранить его.{"$replaceRoot": {"newRoot": {"$mergeObjects": ["$person", {count: "$count"}]}}}
Вы можете попробовать это
db.test.aggregate({ { $group: { _id: '$name',count: { $sum: 1 }, data: { $push: '$$ROOT' } } }, { $project: { _id:0, data:1, count :1 } } }
источник
Я так и сделал, все работает нормально.
db.person.aggregate([ { $group: { _id: '$name'}, // pass the set of field to be grouped age : { $first: '$age' }, // retain remaining field count: { $sum: 1 } // count based on your group }, { $project:{ name:"$_id.name", age: "$age", count: "$count", _id:0 } }])
источник
Просто быстрое обновление, если возникает такая же проблема с документами с большим количеством полей. Можно использовать силу объединения стадии
$replaceRoot
конвейера и$mergeObjects
оператора конвейера.db.users.aggregate([ { $group: { _id: '$name', user: { $first: '$$ROOT' }, count: { $sum: 1 } }, }, { $replaceRoot: { newRoot: { $mergeObjects: [{ count: '$count' }, '$user'] } } } ])
источник
Используйте
$first
с$$ROOT
документом, а затем используйте$replaceRoot
с первым полем.db.test.aggregate([ { "$group": { "_id": "$name", "doc": { "$first": "$$ROOT" } }}, { "$replaceRoot": { "newRoot": "$doc" }} ])
источник
Я не знал о
.group
помощнике, но если вы предпочитаете использовать Aggregation Framework , вам придется указать, какие поля возвращать. Поправьте меня, если я ошибаюсь, но в SQL вам все равно придется это делать.Что ж, вот как вы бы сделали это с упомянутой ранее Aggregation Framework:
db.test.aggregate({ $group: { _id: { name: "$name", city: "$city", fieldName: "$fieldName" }, count: { $sum: 1 } } })
источник
Я создал эту функцию, чтобы обобщить реверсирование стадии размотки ... дайте мне знать, если вы, ребята, столкнетесь с какими-либо ошибками, но у меня она работает хорошо!
const createReverseUnwindStages = unwoundField => { const stages = [ // // Group by the unwound field, pushing each unwound value into an array, // // Store the data from the first unwound document // (which should all be the same apart from the unwound field) // on a field called data. // This is important, since otherwise we have to specify every field we want to keep individually. // { $group: { _id: '$_id', data: {$first: '$$ROOT'}, [unwoundField]: {$push: `$${unwoundField}`}, }, }, // // Copy the array of unwound fields resulting from the group into the data object, // overwriting the singular unwound value // { $addFields: {[`data.${unwoundField}`]: `$${unwoundField}`}, }, // // Replace the root with our data object // { $replaceRoot: { newRoot: '$data', }, }, ] return stages }
источник
Если вы хотите спроецировать все поля документа, используйте запрос ниже.
db.persons.aggregate({ { $group: { _id: '$name', data: { $push: '$$ROOT' }, total: { $sum: 1 }} }, { $project: { _id:0, data:1, total :1 } } }
источник
Вот ответ >>>>
$m = new \MongoDB\Driver\Manager(); $command = new \MongoDB\Driver\Command([ 'aggregate' => 'mytestusers', 'pipeline' => [ ['$match' => ['name' => 'Pankaj Choudhary']], ['$unwind'=>'$skills'], ['$lookup' => array('from'=>'mytestskills','localField'=>'skills','foreignField'=>'_id','as'=>'sdfg')], ['$unwind'=>'$sdfg'], ['$group'=>array('_id'=>array('_id'=>'$_id','name'=>'$name','email'=>'$email'),'skills'=>array('$push'=>'$skills'),'sdfg'=>array('$push'=>'$sdfg'))], ], 'cursor' => new \stdClass, ]); $cursor = $m->executeCommand('targetjob-plus', $command); $result = $cursor->toArray();
источник