Mongodb агрегат показать счетчик с нулевым значением на нескольких полях
Я пытался применить агрегацию на нескольких полях, чтобы показать количество, но это не работает.
У меня есть от 4 до 5 различных значений, скажем, value1,value2,value3,value4,value5, но это не является фиксированным, это может быть очень повторяющиеся значения. Я хочу отобразить это значение с относительным счетом, как мой вывод, и он также должен показать значение field2 и считать с результирующим выводом.
Вот мой запрос
db.Collection.aggregate([
{ $group: {
{
"_id": {field1:"$field1",field2:"$field2"}
}
},
{
"count": { "$sum": 1 }
}
]);
Вот мои данные
{
"_id" : "1",
"field1" : "value1",
"field2" : "abc"
}
{
"_id" : "2",
"field1" : "value2",
"field2" : "xyz"
}
{
"_id" : "3",
"field1" : "value2",
"field2" : "abc"
}
{
"_id" : "4",
"field1" : "value3",
"field2" : "abc"
}
{
"_id" : "5",
"field1" : "value1",
"field2" : "xyz"
}
{
"_id" : "6",
"field1" : "value3",
"field2" : "xyz"
}
{
"_id" : "7",
"field1" : "value1",
"field2" : "abc"
}
{
"_id" : "8",
"field1" : "value2",
"field2" : "xyz"
}
{
"_id" : "9",
"field1" : "value1",
"field2" : "abc"
}
{
"_id" : "10",
"field1" : "value1",
"field2" : "abc"
}
{
"_id" : "11",
"field1" : "value2",
"field2" : "xyz"
}
и мой вывод предположить, что это нравится:
{
"field1.value1" : 0
}
{
"field1.value2" : 1
}
{
"field1.value3" : 12
}
{
"field2.abc" : 50
}
{
"field2.xyz" : 5
}
Дайте мне знать, как это возможно.
2 ответа
Этап $group позволяет вам иметь _id для нескольких полей. Это создает группировку для всех существующих комбинаций ваших различных полей.
Прежде всего, поле счета и сумма накопителя должны находиться в групповой стадии.
db.collection.aggregate([
{ $group: {
{
"_id": { field1:"$field1", field2:"$field2" },
"count": { "$sum": 1 }
}
}
]);
Затем вы можете суммировать результаты на стороне клиента по уменьшенному количеству записей. Это займет незначительное количество времени, так как количество уникальных значений 'field1' и 'field2' будет очень меньше по сравнению с исходным набором документов.
Другой вариант, о котором я могу подумать, - это использовать несколько запросов агрегации, но это зависит только от вас, в зависимости от производительности.
Вы можете сделать это с $objectToArray
оператор в 3.4.
db.foo.aggregate([
{$project: {x: {$objectToArray: "$$CURRENT"}}}
,{$unwind: "$x"}
,{$match: {"x.k": {$ne: "_id"}}}
,{$group: {_id: {f:"$x.k", v: "$x.v"}, n: {$sum:1}}}
,{$project: {fv: {$concat: [ "$_id.f", ".", "$_id.v" ]}, n:1, _id:0 }}
]);
Это динамически работает на любом количестве полей. Если вы хотите ограничить то, что он делает, то добавьте {$match: {"$x.k": {$ne: "fieldname you don't want"}}}
Это выходные данные с учетом данных, размещенных выше:
{ "n" : 5, "fv" : "field2.xyz" }
{ "n" : 4, "fv" : "field1.value2" }
{ "n" : 2, "fv" : "field1.value3" }
{ "n" : 6, "fv" : "field2.abc" }
{ "n" : 5, "fv" : "field1.value1" }
Вот решение, которое соответствует точным спецификациям с помощью $arrayToObject
"повторно синтезировать" документ с нужными именами полей:
db.foo.aggregate([
{$project: {x: {$objectToArray: "$$CURRENT"}}}
,{$unwind: "$x"}
,{$match: {"x.k": {$ne: "_id"}}}
,{$group: {_id: {f:"$x.k", v: "$x.v"}, n: {$sum:1}}}
,{$project: { _id:0, xx: [ [ {$concat: ["$_id.f", ".", "$_id.v"]}, "$n"] ] }}
,{$replaceRoot: { newRoot: {$arrayToObject: "$xx"}}}
]);
Уступая:
{ "field2.xyz" : 5 }
{ "field1.value2" : 4 }
{ "field1.value3" : 2 }
{ "field2.abc" : 6 }
{ "field1.value1" : 5 }