带有 ReferenceField() 的 MongoEngine 条件过滤器
MongoEngine Conditional filter with ReferenceField()
假设有简单的 User
和 Post
模型。
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)
结果是
约翰post
测试 post
管理员 post
我触发了条件 user__ne=hide,所以每隔 posts 打印除了 hide 的 post。
在这种情况下,如何添加更多条件喜欢,性别='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))
但是如果用户的行数过多,可能会出现内存问题。
问题
是否可以一次带条件查询?
.objects() 实际上是在查询数据库吗?
详见兄弟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 可以帮助您实现您想要的(它基本上会复制 gender
中对用户的引用旁边的值25=] 集合)并使其保持同步,但 CachedReferenceField 存在一些错误(以及使它们保持同步的性能问题),因此也许它可以解决简单用例的问题,但我不建议使用它。
2 - .objects()
returns 一个查询集,仅当您遍历查询集(或打印查询集)时才会触发查询。见下文:
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
假设有简单的 User
和 Post
模型。
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)
结果是
约翰post 测试 post 管理员 post
我触发了条件 user__ne=hide,所以每隔 posts 打印除了 hide 的 post。
在这种情况下,如何添加更多条件喜欢,性别='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))
但是如果用户的行数过多,可能会出现内存问题。
问题
是否可以一次带条件查询?
.objects() 实际上是在查询数据库吗?
详见兄弟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 可以帮助您实现您想要的(它基本上会复制 gender
中对用户的引用旁边的值25=] 集合)并使其保持同步,但 CachedReferenceField 存在一些错误(以及使它们保持同步的性能问题),因此也许它可以解决简单用例的问题,但我不建议使用它。
2 - .objects()
returns 一个查询集,仅当您遍历查询集(或打印查询集)时才会触发查询。见下文:
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