2011-11-18 9 views
14

Sto usando Python's mongoengine per interrogare MongoDB e l'ho adorato per la maggior parte, ma sto riscontrando un problema con uno advanced query.MongoDB che utilizza una clausola OR nella mongoengine

Ecco il mio modello

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

vorrei fare una query per tutti ContentItem 's che sono di un determinato account, e sono sia creato da l'utente connesso o sono pubblici. Ecco la domanda che ho scritto

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

o:

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

Ma questi sembrano essere XOR in cui se uno public, oppure il creator ma non entrambi. È previsto?

Sto trascurando qualcosa? Dovrei farlo direttamente con mongodb invece di mongoengine?

La mia soluzione attuale consiste nel creare due query diverse e combinare i risultati, ma man mano che il numero di elementi del contenuto aumenta, il risultato richiede molto tempo per tornare perché è necessario ottenere tutti gli elementi prima di poterli ordinare, perdendo così tutti i benefici di (django) risultati paginati.

risposta

6

In questo caso la documentazione di mongoengine è apparentemente errata. Invece di utilizzare gli operatori bit a bit "&" e "|", è necessario utilizzare gli operatori standard "e" e "o".

Così la vostra prima domanda diventa:

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

che ha fatto il trucco. ho aggiunto una nota sull'account github per correggere la documentazione https://github.com/hmarr/mongoengine/issues/363 – MattoTodd

+0

Questo NON è il caso; vedere il problema github di cui sopra. Ho provato questo, ma usando 'o' invece di' | 'non applicherà il filtro. Usare '&' e '|' funziona bene per me. – Paul

+2

@Paul - forse non hai notato che questo post aveva 9 mesi e che il bug è stato corretto? – apiguy

2

Il modo corretto per fare la query viene a utilizzare le operazioni bit a bit | e & il modo in cui hai scritto nella tua domanda:

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

Nota: utilizzando gli operatori booleani Python standard di and e or sarà non lavoro. Questo è spiegato nel MongoEngine documentation.

0

voi probabilmente importare il Q sbagliato

from mongoengine.queryset.visitor import Q as mongo_Q

from django.db.models import Q as normal_Q

Problemi correlati