Как сделать группу в mongoengine

Предположим, моя схема выглядит так:

class User(Document):
  username = StringField()
  password = StringField()
  category = StringField()

Представьте, что у нас есть эти существующие категории: "avengers", "justice-leaguers", "villains", и я хочу выполнить запрос "group by" для User.objects.all(), чтобы получить что-то вроде этого:

[
 [<User: IronMan object>, <User: Thor object>, <User: Hulk object>], 
 [<User: Superman object>,<User: Batman object>], 
 [<User: Ultron object>, <User: Joker object>, <User: LexLuthor object>]
]

Или еще лучше:

{
 "avengers": [<User: IronMan object>, <User: Thor object>, <User: Hulk object>], 
 "justice-leaguers": [<User: Superman object>,<User: Batman object>], 
 "villains": [<User: Ultron object>, <User: Joker object>, <User: LexLuthor object>]
}

Я просмотрел документы MongoEngine и пока не нашел ничего полезного. Спасибо ребята!


person benjaminz    schedule 12.05.2015    source источник


Ответы (2)


Используя структуру агрегации, вам нужно только $group документы по категориям:

db.User.aggregate([
  {
    $group: { _id: "$category", username: { $push: "$username" }}
  }
])

Используя функцию агрегации $push, вы создадите массив, содержащий все имя пользователя из той же категории.

Учитывая вам образцы данных:

> db.User.find({},{category:1,username:1,_id:0})
{ "category" : "avengers", "username" : "IronMan" }
{ "category" : "avengers", "username" : "Thor" }
{ "category" : "avengers", "username" : "Hulk" }
{ "category" : "justice-leagers", "username" : "Superman" }
{ "category" : "justice-leagers", "username" : "Batman" }
{ "category" : "villains", "username" : "Ultron" }
{ "category" : "villains", "username" : "Joker" }
{ "category" : "villains", "username" : "LexLuthor" }

Это произведет:

{ "_id" : "villains", "username" : [ "Ultron", "Joker", "LexLuthor" ] }
{ "_id" : "justice-leagers", "username" : [ "Superman", "Batman" ] }
{ "_id" : "avengers", "username" : [ "IronMan", "Thor", "Hulk" ] }
person Sylvain Leroux    schedule 12.05.2015
comment
Есть ли шанс, что это можно сделать с помощью Mongoengine? Я, скорее всего, сделаю это в своем коде Python вместо оболочки mongo. Спасибо еще раз! - person benjaminz; 12.05.2015
comment
@benjaminz У меня нет доступа к Mongoengine (и я никогда его не использовал), но, похоже, у него есть необходимый API: mongoengine.queryset.QuerySet.aggregate(*pipeline, **kwargs) - person Sylvain Leroux; 12.05.2015
comment
Проверьте этот ответ: ссылка для использования «группировать по» в mongoengine. - person Yahya; 31.05.2016
comment
Можно ли добавить условия where в эти запросы? - person technazi; 27.06.2019

Поскольку ОП запросил mongoengine (и это то, что мне было нужно), вот пример использования mongoengine:

categories = User.objects.aggregate([{
    '$group': { '_id': '$category', 'username': { '$push': '$username' }}
}])

Это вернет итератор командного курсора pymongo.

print list(categories)

Вернется:

[{ "_id": "villains", "username": ["Ultron", "Joker", "LexLuthor"]},
 { "_id": "justice-leagers", "username": ["Superman", "Batman"]},
 { "_id": "avengers", "username": ["IronMan", "Thor", "Hulk"]}]
person Realistic    schedule 01.11.2015
comment
@SolessChong, это правильный синтаксис. Это список словарей Python. Причина, по которой он больше не работает, возможно, связана с изменением агрегата mongoengine. Чтобы заставить его работать, просто закройте список: User.objects.aggregate({...}) вместо ([{...}]). - person Wtower; 16.12.2016
comment
@Wtower См. редактирование от 21 ноября. В ответе исправлена ​​синтаксическая ошибка. - person SolessChong; 19.12.2016
comment
@SolessChong хорошо, спасибо, что прояснили это. Тем не менее, комментарий относительно списка применим в настоящее время. - person Wtower; 19.12.2016
comment
@Realistic, спасибо за ответ! Не могли бы вы обновить его синтаксисом примера, когда у вас есть более одной категории для группировки. Это то, что будет работать в CLI $group : {_id : {one:"$one", two:"$two"}, но код говорит, что не может кодировать объект. - person hebeha; 24.12.2017