Запрос и группировка вложенных документов с mongoengine - PullRequest
0 голосов
/ 05 июля 2019

У меня есть двоякий вопрос, который уже некоторое время удерживает меня от продолжения.Я прочитал много статей, много раз проверял переполнение стека и снова читал документы mongoengine, но не могу найти ответ, который мне подходит.Я использую mongoDB для хранения данных веб-приложения Flask.Для запроса БД я использую mongoengine.Теперь предположим, что модель моего пользователя выглядит следующим образом:

Users

name: Superman
kudos:
       0 0 date
         1 category A
       1 0 date
         1 category B

name: Superman
kudos:
       0 0 date
         1 category A
       1 0 date
         1 category A
       2 0 date
         1 category B

Кудо - это вложенные документы, которые создаются каждый раз, когда пользователь получает кудо.Я храню их как db.ListField (дата = сейчас).Это прекрасно работает.

В реляционной БД у меня была бы отдельная схема кудо.В mongoDB я предполагаю, что это было бы лучшим решением для создания вложенных документов с коллекциями пользователей.В противном случае вы все еще создаете все виды отдельных схем, которые связаны с другими.

Итак, вот два моих главных вопроса:

  1. Правильно ли я верю в то, что моя архитектура верна тому, как должен быть реализован mongoengine?
  2. Как мне получитьсписок (фактически) кудо на категорию?Поэтому я хотел бы запросить и получить Category - Count

Результат должен быть: kudos = [(категория A, 3), (категория B, 2)

Если я уже имелчто-то даже удаленно работающее, я бы это обеспечил, но я полностью застрял.Вот почему я даже начал сомневаться в том, чтобы хранить репутацию в отдельной коллекции, но мне кажется, что я начинаю правильно ориентироваться с использованием базы данных noSQL.

1 Ответ

0 голосов
/ 05 июля 2019

Предполагается, что у вас есть следующая схема и данные:

import datetime as dt
from mongoengine import *

connect(host='mongodb://localhost:27017/testdb')


class  Kudo(EmbeddedDocument):
    date = DateTimeField(default=dt.datetime.utcnow)
    category = StringField()

class User(Document):
    name = StringField(required=True)
    kudos = EmbeddedDocumentListField(Kudo)


superman = User(name='superman', kudos=[Kudo(category='A')]).save()
batman = User(name='batman', kudos = [Kudo(category='A'), Kudo(category='B')]).save()

Это не самый эффективный, но вы можете получить дистрибутив с помощью следующего простого фрагмента:

import itertools
from collection import Counter

raw_kudos = User.objects.scalar('kudos')
categories_counter = Counter(k.category for k in itertools.chain.from_iterable(raw_kudos))    # raw_kudos is a list of list
print(categories_counter)    # is a dict --> Counter({u'A': 1, u'B': 1})

А если вам нужна более высокая производительность, вам нужно использовать конвейер агрегации

...