MongoDB - Как сгруппировать по дате и посчитать элементы в массиве - PullRequest
1 голос
/ 02 мая 2020

Вот мой пример документа:

{
    "_id" : ObjectId("5eac6572fe57d55a258e645a"),
    "createdAt" : ISODate("2020-05-01T18:07:37.568Z"),
    "user" : ObjectId("5e6dda081c456d3670ba5816"),
    "question" : [
        {
            "round" : 1,
            "attempt" : 1,
            "right" : 0,
            "wrong" : 1,
            "time" : ISODate("2020-05-01T18:07:46.900Z"),
            "_id" : ObjectId("5eac6572fe57d55a258e645b"),
            "questions" : ObjectId("5e81735b286698630dba2be5")
        }
    ],
    "__v" : 0
}

Я хочу сгруппировать по созданному ату и подсчитать общее количество вопросов на эту дату. Я пробовал это, но не повезло

MyModel.aggregate([
            {  $match: { user: req.user._id } },
            {
                $group: {
                    _id: {
                        createdAt: "$createdAt",
                        //question: "$question",
                        //count: {$count: "$question"} // Giving me an error that $count not found
                    }
                },
            }
        ], function(err, docs) {
            if (err) {
                console.log(err);
            } else {
                res.json(docs);
            }
        });

Любая помощь будет оценена. Заранее спасибо!

1 Ответ

2 голосов
/ 02 мая 2020

Попробуйте запрос агрегации ниже:

db.collection.aggregate([
  /** add a new field to each doc with count on `question` array */
  { $addFields: { questionCount: { $size: "$question" } }
  },
  /** group all docs & sum-up question count */
  {
    $group: {
      _id: { createdAt: { $dateToString: { format: "%Y-%m-%d", date: "$createdAt" } } },
      questionCount: { $sum: "$questionCount" }
    }
  }
])

Тест: mongoplayground

Примечание: Вы, безусловно, можете сделать это другим способом, используя $unwind в качестве второго этапа после $match в массиве question и затем путем подсчета количества документов в $group, но $unwind может взорвать вашу коллекцию, если она огромна даже после $match, Так что, возможно, так будет лучше.

Обновление: По предложению @Thee Sritabtim:

db.collection.aggregate([
      /** group all docs & sum-up question count using `$size` on array */
      {
        $group: {
          _id: { createdAt: { $dateToString: { format: "%Y-%m-%d", date: "$createdAt" } } },
          questionCount: { $sum: { $size: "$question" } }
        }
      }
    ])
...