Wszyscy. W zapytaniu grupowym mongo wynik zawiera tylko klucze w argumentach. Jak zachować pierwszy dokument w każdej grupie, np. Mysql query group. na przykład:
-------------------------------------------------------------------------
| 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 } })
wynik:
[
{
"name" : "ddl1st",
"count" : 1
},
{
"name" : "24k",
"count" : 1
}
]
Jak zdobyć:
[
{
"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'}
itp.? Czy można po prostu miećage: $age
?$group
_id, możesz$sort
wcześniej z żądanym polem, a następnie pogrupować i użyć operatorów$first
lub$last
na dowolnym polu. Podczas akumulacji pomysł uwzględnienia innych pól (które są gromadzone / lejkowane / redukowane) nie ma aż tyle sensu, nawet teoretycznie. Jednak sortowanie przed rozdaniem jest w rzeczywistości nieefektywne w porównaniu z sortowaniem każdej grupy w sobie, ponieważ algorytmy sortowania są bardziej złożone niż O (n). Chciałbym, żeby w MongoDB były lepsze sposoby.Nawiasem mówiąc, jeśli chcesz zachować nie tylko pierwszy dokument, możesz użyć $ addToSet Na przykład:
db.test.aggregate({ $group: { _id: '$name', name : { $addToSet: '$name' } age : { $addToSet: '$age' }, count: { $sum: 1 } } }
źródło
[zmieniono w celu uwzględnienia sugestii komentarzy]
Przyszedłem tutaj, szukając odpowiedzi, ale nie byłem zadowolony z wybranej odpowiedzi (szczególnie biorąc pod uwagę wiek). Znalazłem tę odpowiedź, która jest lepszym rozwiązaniem (dostosowanym):
db.test.aggregate({ $group: { _id: '$name', person: { "$first": "$$ROOT" }, count: { $sum: 1 } }, { "$replaceRoot": { "newRoot": { "$mergeObjects": ["$person", { count: "$count" }]} } } }
źródło
count
pole. Musisz$mergeObjects
go zachować.{"$replaceRoot": {"newRoot": {"$mergeObjects": ["$person", {count: "$count"}]}}}
Możesz to wypróbować
db.test.aggregate({ { $group: { _id: '$name',count: { $sum: 1 }, data: { $push: '$$ROOT' } } }, { $project: { _id:0, data:1, count :1 } } }
źródło
Tak właśnie zrobiłem, działa dobrze.
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 } }])
źródło
Tylko szybka aktualizacja, jeśli masz ten sam problem z dokumentami z wieloma polami. Można wykorzystać siłę połączenia
$replaceRoot
etapu rurociągu i$mergeObjects
operatora rurociągu.db.users.aggregate([ { $group: { _id: '$name', user: { $first: '$$ROOT' }, count: { $sum: 1 } }, }, { $replaceRoot: { newRoot: { $mergeObjects: [{ count: '$count' }, '$user'] } } } ])
źródło
Użyj
$first
z$$ROOT
dokumentem, a następnie użyj$replaceRoot
z pierwszym polem.db.test.aggregate([ { "$group": { "_id": "$name", "doc": { "$first": "$$ROOT" } }}, { "$replaceRoot": { "newRoot": "$doc" }} ])
źródło
Nie wiedziałem o
.group
pomocniku, ale jeśli wolisz korzystać ze schematu agregacji , musisz określić, które pola mają zwrócić. Popraw mnie, jeśli się mylę, ale w SQL i tak musiałbyś to zrobić.Cóż, w ten sposób można to zrobić za pomocą wspomnianej wcześniej struktury agregacji:
db.test.aggregate({ $group: { _id: { name: "$name", city: "$city", fieldName: "$fieldName" }, count: { $sum: 1 } } })
źródło
Stworzyłem tę funkcję, aby uogólnić cofanie fazy odprężenia ... daj mi znać, jeśli napotkacie jakieś błędy, ale dla mnie działa dobrze!
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 }
źródło
Jeśli chcesz wyświetlić wszystkie pola, udokumentuj to, użyj poniższego zapytania.
db.persons.aggregate({ { $group: { _id: '$name', data: { $push: '$$ROOT' }, total: { $sum: 1 }} }, { $project: { _id:0, data:1, total :1 } } }
źródło
Oto odpowiedź >>>>
$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();
źródło