2011-11-18 111 views
14

我使用python的mongoengine來查詢MongoDB,並且大部分都非常喜歡它,但是我遇到了advanced query的問題。MongoDB在mongoengine中使用OR子句

這裏是我的模型

class ContentItem(Document): 
    account = ReferenceField(Account) 
    creator = ReferenceField(User) 
    public = BooleanField(default=False) 
    last_used = DateTimeField(default=datetime.now) 

我想提出的所有ContentItem的是一個特定賬戶的查詢,並通過登錄的用戶或者是公共要麼創建。下面是我寫的

query = ContentItem.objects.filter((Q(account=account) & Q(public=True)) | (Q(account=account) & Q(creator=logged_in_user))).order_by('-last_used') 

或查詢:

query = ContentItem.objects.filter(Q(account=account) & (Q(public=True) | Q(creator=logged_in_user))).order_by('-last_used') 

但這些似乎是XOR其中如果任public,或creator但不能同時。這是預期的嗎?

我可以俯視嗎?我應該直接用mongodb而不是mongoengine來做這個嗎?

我目前的解決方法是做兩個不同的查詢併合並結果,但隨着內容項的數量越來越大,結果需要很長時間才能回來,因爲我需要先獲取所有項目,然後才能訂購它們,從而失去了(django)分頁結果的所有好處。

回答

6

在這種情況下,mongoengine文檔顯然不正確。不應使用按位運算符「&」和「|」,應使用標準運算符「和」和「或」。

所以,你的第一個查詢就變成了:

query = ContentItem.objects.filter((Q(account=account) and Q(public=True)) or (Q(account=account) and Q(creator=logged_in_user))).order_by('-last_used') 
+0

該訣竅。我在github帳戶上添加了一個註釋來修復文檔https://github.com/hmarr/mongoengine/issues/363 – MattoTodd

+0

這不是這種情況;請參閱上面引用的github問題。我嘗試過,但使用'或'而不是'|'不會應用過濾器。使用'&'和'|'對我來說工作得很好。 – Paul

+2

@Paul - 也許你沒有注意到這篇文章已經9個月了,而且這個bug已經被修復了? – apiguy

1

https://github.com/MongoEngine/mongoengine/blob/master/tests/queryset/transform.py

線134

高清test_raw_query_and_Q_objects(個體經營):

query = Foo.objects(__raw__={'$nor': [{'name': 'bar'}]})._query 
    self.assertEqual(query, {'$nor': [{'name': 'bar'}]}) 

    q1 = {'$or': [{'a': 1}, {'b': 1}]} 
    query = Foo.objects(Q(__raw__=q1) & Q(c=1))._query 
    self.assertEqual(query, {'$or': [{'a': 1}, {'b': 1}], 'c': 1}) 
2

做查詢正確的方法是使用按位運算|&你在你的問題寫的方式:

query = ContentItem.objects.filter((Q(account=account) & Q(public=True)) | (Q(account=account) & Q(creator=logged_in_user))).order_by('-last_used') 

:使用標準的Python布爾運算符andor工作。這在MongoEngine documentation中有解釋。

0

你可能導入了錯誤的Q

from mongoengine.queryset.visitor import Q as mongo_Q

from django.db.models import Q as normal_Q