#mongodb #mongoengine
#mongodb #mongoengine
Вопрос:
Предположим, что существует simple User
и Post
model.
class User(Document):
user_id = StringField(primary_key=True)
gender = StringField(default='M')
class Post(Document):
user = ReferenceField(User)
body = StringField()
if __name__ == '__main__':
hide = User(user_id='hide', gender='M').save()
john = User(user_id='john', gender='M').save()
test = User(user_id='test', gender='W').save()
admin = User(user_id='admin', gender='W').save()
Post(user=hide, body='hide post').save()
Post(user=john, body='john post').save()
Post(user=test, body='test post').save()
Post(user=admin, body='admin post').save()
hide = User.objects(user_id='hide').first()
posts = Post.objects(user__ne=hide)
for post in posts:
print(post.body)
Результатом является
джон пост тестовый пост, сообщение администратора
Я запустил условие user__ne = скрыть, поэтому печатаются все сообщения, кроме сообщения hide.
В этом случае, как я могу добавить больше лайков условию, gender =’W’?
Приведенный ниже код является результатом моих попыток.
posts = Post.objects(user__ne=hide, user__gender__ne='M')
и
from mongoengine.queryset.visitor import Q
posts = Post.objects(Q(user__ne=hide) amp; Q(user__gender__ne='M'))
Но оба кода выдают ошибки -> mongoengine.errors.InvalidQueryError: Cannot perform join in mongoDB: user__gender
Я знаю, что это может быть реализовано с помощью этого.
gender = User.objects(gender__ne='M')
posts = Post.objects(Q(user__ne=hide) amp; Q(user__nin=gender))
Но если у пользователей слишком много строк, возможно, возникает проблема с памятью.
Вопрос
-
Возможно ли выполнить запрос с условием сразу?
-
Действительно ли .objects() запрашивает базу данных?
Ответ №1:
Как подробно описано в родственном тикете на github
1 — В mongodb нет объединений, поэтому нет другого варианта, кроме того, который вы предложили. Одна простая вещь, которую вы можете сделать для повышения производительности и уменьшения занимаемой памяти, — это извлекать только идентификаторы пользователей, см. Ниже:
male_ids = User.objects(gender__ne='M').scalar('id') # Only fetch the user ids, i.o loading full object data into User model
posts = Post.objects(Q(user__ne=hide) amp; Q(user__nin=male_ids))
Примечание: В mongoengine есть CachedReferenceField, которое может помочь вам достичь желаемого (оно в основном дублирует значение gender
рядом со ссылкой на пользователя в коллекции Post) и синхронизировать его, но CachedReferenceField страдает от некоторых ошибок (и проблемы с производительностью для их синхронизации), поэтому, возможно, оно могло бы подойти для простых вариантов использования, но я бы не советовал его использовать.
2 — .objects()
возвращает набор запросов, запрос запускается только при выполнении итерации по набору запросов (или печати набора запросов). Смотрите ниже:
user_qs = User.objects()
print(type(user_qs)) # <class mongoengine.queryset.queryset.QuerySet>, query not fired yet
for user in qs_user: # fires the actual query and load data in User instances
pass