в моем проекте у меня есть пользователи, которые заканчивают комбинации (называемые сессиями) курсов. сам факт прохождения курса называется попыткой. Во время попытки они могут закрыть его и вернуться позже (поэтому мы храним объект timelog).
У меня есть запрос от клиента, который должен возвращать для каждого сеанса пользователей (и их попытки), которые сыграли весь или часть своего сеанса в течение определенного периода времени.
В течение определенного периода времени означает, что клиент отправляет дату начала и окончания, и мы считаем пользователя для определенного сеанса, если:
- первая попытка началась до истечения таймфрейма => начало первого таймлога первой <дата окончания
- последняя попытка была завершена после начала таймфрейма => конец последнего таймлога последней попытки> дата начала
Вот пример объекта попытки (единственный, который нам нужно использовать здесь):
{
"_id" : ObjectId("5b9148650ab5f43b5e829a4b"),
"index" : 0,
"author" : ObjectId("5acde2646055980a84914b6b"),
"timelog" : [
{
"started" : ISODate("2018-09-06T15:31:49.163Z"),
"ended" : ISODate("2018-09-06T15:32:03.935Z")
},
...
],
"session" : ObjectId("5b911d31e58dc13ab7586f9b")}
- Моя идея состояла в том, чтобы объединить попытки, сгруппировать тех, кто использует
author
и session
в качестве _id
для этапа $group
, и отодвинуть все попытки пользователя для этого конкретного сеанса. в массив userAttempts
.
- Затем создать этап $ addField для извлечения начального поля первого временного журнала первой попытки и последнего конца последней попытки.
- И, наконец, $ filter или $ match с использованием этих новых полей.
Вот мой агрегат:
const newDate = new Date()
_db.attempts.aggregate([
{ $match: {
author: { $in: programSessionsData.users },
$or: [{ programSession: { $in: programSessionIds } }, { oldTryFor: { $in: programSessionIds } }],
globalTime: $ex,
timelog: $ex }
},
{
$group: {
_id: {
user: "$author",
programSession: "$programSession"
},
userAttempts: { $push: { attemptId: "$_id", lastTimelog: { $arrayElemAt: ["$timelog", -1] }, timelog: "$timelog" } }
}
},
{
$addFields: { begin: { $reduce: {
input: "$userAttempts",
initialValue: newDate,
in: {
$cond: {
if: { $lt: ["$$this.timelog.0.started", "$$value"] },
then: "$$this.timelog.0.started",
else: "$$value"
} }
} } }
}
Я также пробовал это на этапе addFields:
{
$addFields: { begin: { $reduce: {
input: "$userAttempts",
initialValue: newDate,
in: { $min: ["$$this.timelog.0.started", "$$value] }
} } }
}
Однако каждый раз начало - это пустой массив.
Я действительно не знаю, как я могу извлечь эти две даты или сравнить даты между ними.
К сведению : конец сложнее, поэтому мне нужно сначала извлечь lastTimelog. Если бы вы использовали другой метод, я бы с радостью воспользовался им.
Также этот код находится на сервере узлов, поэтому я не могу использовать ISODate. и используемая версия монго - 3.6.3.