MongoDB, используя предложение OR в mongoengine - PullRequest
17 голосов
/ 19 ноября 2011

Я использую python's mongoengine для запроса MongoDB, и мне очень понравилось, но у меня проблема с расширенным запросом .

Вот моя модель

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) постраничных результатов.

Ответы [ 5 ]

9 голосов
/ 22 ноября 2011

В данном случае документация 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')
3 голосов
/ 17 ноября 2015

Правильный способ выполнения запроса - использовать побитовые операции | и & так, как вы написали это в своем вопросе:

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

Примечание : использование стандартных булевых операторов Python and и or будет не работать. Это объясняется в документации MongoEngine .

2 голосов
/ 31 мая 2019

Документы MongoEngine говорят об обратном.Пожалуйста, проверьте это: http://docs.mongoengine.org/guide/querying.html

1 голос
/ 28 ноября 2017

вы, вероятно, импортируете неправильный Q

from mongoengine.queryset.visitor import Q as mongo_Q

from django.db.models import Q as normal_Q

1 голос
/ 17 апреля 2015

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

строка 134

def test_raw_query_and_Q_objects (self):

    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})
...