MongoDB usando uma cláusula OR em mongoengine

votos
15

Estou usando mongoengine de python para consultar MongoDB, e amei-lo para a maior parte, mas eu estou tendo um problema com uma consulta avançada .

Aqui está o meu modelo

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

Eu gostaria de fazer uma consulta para todos ContentItem's que são de uma conta particular, e são ambos criados pelo usuário conectado ou são públicas. Aqui está a consulta que eu escrevi

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

ou:

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

Mas estes parecem ser XOR onde se quer public, ou o creatormas não ambos. É este o esperado?

Estou com vista para alguma coisa? Devo fazer isso diretamente com o MongoDB em vez de mongoengine?

Minha solução atual é a de fazer duas consultas diferentes e combinar os resultados, mas como o # de itens de conteúdo se torna maior o resultado está levando muito tempo para voltar, porque eu preciso para obter todos os itens antes de eu pode encomendá-los, perdendo assim toda a benefício de (Django) resultados paginados.

Publicado 18/11/2011 em 23:00
fonte usuário
Em outras línguas...                            


5 respostas

votos
7

A documentação mongoengine é aparentemente incorreta neste caso. Em vez de usar os operadores bit a bit "&" e "|", você deve usar os operadores padrão "e" e "ou".

Portanto, sua primeira consulta torna-se:

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')
Respondeu 21/11/2011 em 22:34
fonte usuário

votos
1

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

A linha 134

test_raw_query_and_Q_objects def (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})
Respondeu 17/04/2015 em 19:09
fonte usuário

votos
2

A maneira correta de fazer a consulta é usar operações bit a bit |e &da maneira que você escreveu na sua pergunta:

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

Nota : usando os operadores booleanos padrão do Python ande orserá não funcionam. Isto é explicado na documentação MongoEngine .

Respondeu 17/11/2015 em 13:10
fonte usuário

votos
0

você provavelmente está importar o Q errado

from mongoengine.queryset.visitor import Q as mongo_Q

from django.db.models import Q as normal_Q

Respondeu 28/11/2017 em 15:07
fonte usuário

votos
0

docs MongoEngine dizer o contrário. Por favor, checar isto: http://docs.mongoengine.org/guide/querying.html

Respondeu 31/05/2019 em 23:10
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more