【问题标题】:MongoEngine Conditional filter with ReferenceField()带有 ReferenceField() 的 MongoEngine 条件过滤器
【发布时间】:2019-03-27 03:35:09
【问题描述】:

假设有简单的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,所以除了 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) & 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() 是否真的查询数据库?

【问题讨论】:

    标签: mongodb mongoengine


    【解决方案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 - .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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-29
      • 1970-01-01
      • 2014-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多