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 }
Другие вопросы по тегам