具有ReferenceField()的MongoEngine条件过滤器

时间:2019-03-27 03:35:10

标签: mongodb mongoengine

假设有简单的UserPost模型。

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,所以除了隐藏的帖子之外,所有已打印的帖子。

在这种情况下,如何添加更多喜欢的条件,性别=“ W”?

下面的代码是我尝试过的结果。

posts = Post.objects(user__ne=hide, user__gender__ne='M')

from mongoengine.queryset.visitor import Q

posts = Post.objects(Q(user__ne=hide) & 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) & Q(user__nin=gender))

但是,如果用户的行太多,则可能发生内存问题。

问题

  1. 是否可以一次查询条件?

  2. .objects()是否实际查询数据库?

1 个答案:

答案 0 :(得分:1)

如同级github ticket

所述

1-mongodb中没有连接,因此除了您建议的选项外没有其他选项。您可以提高性能并减少内存占用的简单方法是仅获取用户ID,请参见下文:

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) & Q(user__nin=male_ids))

注意:mongoengine中有一个CachedReferenceField,可以帮助您实现所需的目标(它基本上会复制Post集合中对用户的引用旁边的gender的值),并且使其保持同步,但是CachedReferenceField会遇到一些错误(以及使它们保持同步的性能问题),因此也许它可以解决简单的用例,但我不建议您使用它。

2-{{​​1}}返回一个查询集,仅当您遍历该查询集(或打印该查询集)时才触发该查询。见下文:

.objects()