Todo mundo. Na consulta de grupo mongo, o resultado mostra apenas a (s) chave (s) nos argumentos. Como manter o primeiro documento em cada grupo, como o grupo de consulta mysql. por exemplo:
-------------------------------------------------------------------------
| 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 } })
resultado:
[
{
"name" : "ddl1st",
"count" : 1
},
{
"name" : "24k",
"count" : 1
}
]
Como obter o seguinte:
[
{
"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'}
etc.? É possível apenas terage: $age
?$group
_id, você pode$sort
antes com o campo desejado agrupar e usar$first
ou$last
operadores em qualquer campo. Ao acumular, a ideia de incluir outros campos (que são acumulados / afunilados / reduzidos) não faz muito sentido, mesmo teoricamente. No entanto, a classificação antecipada é realmente ineficiente em comparação com a classificação de cada grupo dentro deles, uma vez que os algoritmos de classificação são mais complexos do que O (n). Eu gostaria que houvesse maneiras melhores no MongoDB.A propósito, se você quiser manter não apenas o primeiro documento, pode usar $ addToSet. Por exemplo:
db.test.aggregate({ $group: { _id: '$name', name : { $addToSet: '$name' } age : { $addToSet: '$age' }, count: { $sum: 1 } } }
fonte
[editado para incluir sugestões de comentários]
Vim aqui à procura de uma resposta, mas não fiquei satisfeito com a resposta selecionada (especialmente devido à sua idade). Achei esta resposta que é uma solução melhor (adaptada):
db.test.aggregate({ $group: { _id: '$name', person: { "$first": "$$ROOT" }, count: { $sum: 1 } }, { "$replaceRoot": { "newRoot": { "$mergeObjects": ["$person", { count: "$count" }]} } } }
fonte
count
campo. Você precisa usar$mergeObjects
para mantê-lo.{"$replaceRoot": {"newRoot": {"$mergeObjects": ["$person", {count: "$count"}]}}}
Você pode experimentar isto
db.test.aggregate({ { $group: { _id: '$name',count: { $sum: 1 }, data: { $push: '$$ROOT' } } }, { $project: { _id:0, data:1, count :1 } } }
fonte
Isso é o que eu fiz, funciona bem.
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 } }])
fonte
Apenas uma atualização rápida se alguém enfrentar o mesmo problema com documentos com vários campos. Pode-se usar o poder de combinar o
$replaceRoot
estágio do$mergeObjects
oleoduto e o operador do oleoduto.db.users.aggregate([ { $group: { _id: '$name', user: { $first: '$$ROOT' }, count: { $sum: 1 } }, }, { $replaceRoot: { newRoot: { $mergeObjects: [{ count: '$count' }, '$user'] } } } ])
fonte
Use
$first
com o$$ROOT
documento e depois use$replaceRoot
com o primeiro campo.db.test.aggregate([ { "$group": { "_id": "$name", "doc": { "$first": "$$ROOT" } }}, { "$replaceRoot": { "newRoot": "$doc" }} ])
fonte
Eu não sabia sobre o
.group
helper, mas se você preferir usar o Aggregation Framework , você terá que especificar quais campos retornar. Corrija-me se eu estiver errado, mas no SQL você teria que fazer isso de qualquer maneira.Bem, é assim que você faria com a estrutura de agregação mencionada anteriormente:
db.test.aggregate({ $group: { _id: { name: "$name", city: "$city", fieldName: "$fieldName" }, count: { $sum: 1 } } })
fonte
Eu criei esta função para generalizar a reversão de um estágio de desenrolamento ... deixe-me saber se vocês encontraram algum bug com ela, mas está funcionando bem para mim!
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 }
fonte
Se você deseja projetar todos os campos do documento, use a consulta abaixo.
db.persons.aggregate({ { $group: { _id: '$name', data: { $push: '$$ROOT' }, total: { $sum: 1 }} }, { $project: { _id:0, data:1, total :1 } } }
fonte
Aqui está a resposta >>>>
$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();
fonte