Поставлена такая задача:
В коллекции пользователей 'Account' лежат документы вида:
{
'number': '7800000000000',
'name': 'Пользователь №',
'sessions': [
{
'created_at': ISODate('2016-01-01T00:00:00'),
'session_id': '6QBnQhFGgDgC2FDfGwbgEaLbPMMBofPFVrVh9Pn2quooAcgxZc',
'actions': [
{
'type': 'read',
'created_at': ISODate('2016-01-01T01:20:01'),
},
{
'type': 'read',
'created_at': ISODate('2016-01-01T01:21:13'),
},
{
'type': 'create',
'created_at': ISODate('2016-01-01T01:33:59'),
}
],
}
]
}
Необходимо написать агрегационный запрос, который по каждому пользователю выведет последнее действие и общее количество для каждого из типов 'actions'. Итоговые данные должны представлять собой список документов вида:
{
'number': '7800000000000',
'actions': [
{
'type': 'create',
'last': 'created_at': ISODate('2016-01-01T01:33:59'),
'count': 12,
},
{
'type': 'read',
'last': 'created_at': ISODate('2016-01-01T01:21:13'),
'count': 12,
},
{
'type': 'update',
'last': null,
'count': 0,
},
{
'type': 'delete',
'last': null,
'count': 0,
},
]
}
Написал три таких модели:
class Account(Model):
number = AutoField(primary_key=True, verbose_name='Номер')
name = CharField(max_length=20, verbose_name='Имя')
class Session(Model):
user = ForeignKey(Account, on_delete=CASCADE, related_name='sessions', verbose_name='Пользователь')
session_id = CharField(max_length=session_id_max_length, blank=True, editable=False, unique=True, verbose_name='ID сессии')
created_at = DateTimeField(auto_now_add=True, verbose_name='Дата создания')
class Action(Model):
class Type(TextChoices):
CREATE = 'create', 'Создание'
READ = 'read', 'Чтение'
UPDATE = 'update', 'Изменение'
DELETE = 'delete', 'Удаление'
session = ForeignKey(Session, on_delete=CASCADE, related_name='actions', verbose_name='Сессия')
type = CharField(max_length=6, choices=Type.choices, verbose_name='Тип')
created_at = DateTimeField(auto_now_add=True, verbose_name='Дата создания')
Как можно видеть, таблицы связаны между собой по цепочке через FK, Account <- Session <- Action, то есть из модели Account нельзя получить объекты модели Action напрямую.
Все, чего я смог добиться на данный момент - это запрос вида
Action.objects.values('session__user__number', 'type').annotate(last=Max('created_at'), count=Count('type'))
Он возвращает QuerySet вида
<QuerySet [
{'session__user__number': 1, 'type': 'update', 'last': datetime.datetime(2021, 6, 16, 16, 56, 55, 370580, tzinfo=<UTC>), 'count': 1},
{'session__user__number': 2, 'type': 'read', 'last': datetime.datetime(2021, 6, 16, 17, 23, 17, 215523, tzinfo=<UTC>), 'count': 1},
{'session__user__number': 2, 'type': 'update', 'last': datetime.datetime(2021, 6, 16, 16, 56, 11, 916884, tzinfo=<UTC>), 'count': 2}
]>
что достаточно близко, но нет группировки по пользователям ('session__user__number': 2 дублируется два раза).
Есть ли какой-то способ получить результат, максимально близкий к образцу, без дополнительных манипуляций с QuerySet'ом после выполнения запроса?