MongoDB с использованием предложения OR в mongoengine

Я использую python 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) paginated results.

Ответы

Ответ 1

Документация 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')

Ответ 2

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

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.

Ответ 3

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

Ответ 4

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

from mongoengine.queryset.visitor import Q as mongo_Q

from django.db.models import Q as normal_Q