Mongodb агрегат $ группа для несуществующих элементов - PullRequest
1 голос
/ 12 февраля 2020

У меня есть такой документ:

Документы:

{score: 1, value: 10}
{score: 3, value: 10}
{score: 1, value: 10}
{score: 4, value: 10}
{score: 1, value: 10}
{score: 5, value: 10}
{score: 5, value: 10}
{score: 10, value: 10}

В этой коллекции нет баллов за 2,6,7,8,9 но мне нужен вывод, как показано ниже.

Вывод:

{score: 1, avg: 10}
{score: 2, avg: 0}
{score: 3, avg: 10}
{score: 4, avg: 10}
{score: 5, avg: 10}
{score: 6, avg: 0}
{score: 7, avg: 0}
{score: 8, avg: 0}
{score: 9, avg: 0}
{score: 10, avg: 10}

Любая опция в Mon go агрегат, которая будет генерировать это. Пожалуйста, помогите

Ответы [ 2 ]

2 голосов
/ 12 февраля 2020

Вы можете попробовать это, используя агрегацию :

db.collection.aggregate([
    { $group: { _id: '$score', avg: { $avg: '$value' } } },
    { $group: { _id: '', min: { $min: '$_id' }, max: { $max: '$_id' }, data: { $push: '$$ROOT' } } },
    { $project: { _id: 0, data: 1, nums: { $range: ['$min', "$max", 1] } } },
    { $project: { data: { $concatArrays: ["$data", { $map: { input: { $setDifference: ["$nums", "$data._id"] }, in: { _id: '$$this', avg: 0 } } }] } } },
    { $unwind: '$data' }, { $replaceRoot: { newRoot: "$data" } }
])

Тест: MongoDB-Playground

0 голосов
/ 12 февраля 2020

Предполагая, что вы знаете диапазон баллов, есть хитрость для достижения именно того, что вы хотите:

1 - Вставьте в свою коллекцию документ для каждого балла, если поле значения не установлено или не установлено в ноль:

db.collection.insertMany([
  {
    score: 1,
  },
  {
    score: 2,
  },
  {
    score: 3,   
  },
  {
    score: 4,    
  },
  {
    score: 5,   
  },
  {
    score: 6,  
  },
  {
    score: 7,    
  },
  {
    score: 8,    
  },
  {
    score: 9, 
  },
  {
    score: 10,
  }
]);

Важно, чтобы поле значения не устанавливалось, поскольку значение, установленное на 0, повлияет на вычисление среднего значения

Конечно, эту операцию необходимо выполнить только один раз.

Затем вы можете применить следующую агрегацию, которая будет выводить именно то, что вам нужно:

db.collection.aggregate([
  {
    $bucket: {
      groupBy: "$score",
      boundaries: [
        0,
        1,
        2,
        3,
        4,
        5,
        6,
        7,
        8,
        9,
        10,
        11
      ],
      output: {
        avg: {
          $avg: "$value"
        }
      }
    }
  },
  {
    $project: {
      score: "$_id",
      avg: {
        $ifNull: [
          "$avg",
          0
        ]
      },
      _id: 0
    }
  }
])

Будет выводить:

[
  {
    "avg": 10,
    "score": 1
  },
  {
    "avg": 0,
    "score": 2
  },
  {
    "avg": 10,
    "score": 3
  },
  {
    "avg": 10,
    "score": 4
  },
  {
    "avg": 10,
    "score": 5
  },
  {
    "avg": 0,
    "score": 6
  },
  {
    "avg": 0,
    "score": 7
  },
  {
    "avg": 0,
    "score": 8
  },
  {
    "avg": 0,
    "score": 9
  },
  {
    "avg": 10,
    "score": 10
  }
]

Вы можете проверить это здесь .

...