2010-01-05 8 views
35

J'ai donc un document incorporé qui suit les appartenances aux groupes. Chaque document incorporé a un ID pointant vers le groupe dans une autre collection, une date de début et une date d'expiration optionnelle.Requête MongoDB avec une condition 'ou'

Je souhaite interroger les membres actuels d'un groupe. "Actuel" signifie que l'heure de début est inférieure à l'heure actuelle, et que l'heure d'expiration est supérieure à l'heure actuelle OU nulle.

Cette requête conditionnelle me bloque totalement. Je pourrais le faire en exécutant deux requêtes et en fusionnant les résultats, mais cela semble moche et exige le chargement dans tous les résultats immédiatement. Ou je pourrais par défaut le temps d'expiration à une date arbitraire dans un avenir lointain, mais cela semble encore plus laide et potentiellement fragile. En SQL, je l'exprimerais simplement avec "(expires> = Now()) OR (expire IS NULL)" - mais je ne sais pas comment le faire dans Mongo.

Des idées? Merci d'avance.

+0

question Analogie: http://stackoverflow.com/questions/1945577/logique-ou-pour-deux-différents-champs-dans-où-requêtes-dans-mongodb –

Répondre

66

Je pensais juste mettre à jour au cas où quelqu'un tomberait sur cette page dans le futur. À partir de 1.5.3, mongo soutient maintenant un vrai $ ou opérateur: http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24or

Votre requête de "(expire> = maintenant()) OR (expiration IS NULL)" peut maintenant être rendu comme:

{$or: [{expires: {$gte: new Date()}}, {expires: null}]} 
2

Query objects in Mongo by default AND expressions together. Mongo currently does not include an OR operator for such queries, however there are ways to express such queries.

utilisation "dans" ou "où".

ça va être quelque chose comme ceci:

db.mycollection.find({ $where : function() { 
return (this.startTime < Now() && this.expireTime > Now() || this.expireTime == null); } }); 
+0

Assez cool, la première fois que je vois une fonction utilisée avec Mongo !! L'inconvénient bien sûr, je suppose, est qu'il n'utilisera pas les index – Nico

1

L'utilisation d'un $ où la requête sera lente, en partie parce qu'il ne peut pas utiliser les index. Pour ce genre de problème, je pense qu'il serait préférable de stocker une valeur élevée pour le champ "expires" qui sera naturellement toujours plus grand que Now(). Vous pouvez soit stocker une très haute date des millions d'années dans le futur, ou utiliser un type de seporate pour indiquer jamais. L'ordre de tri de type croisé est défini à http://www.mongodb.org/display/DOCS/Compare+Order+for+Types. Un Regex ou un MaxKey vide (si votre langue le supporte) sont deux bons choix.

33

Si quelqu'un trouve cela utile, www.querymongo.com fait la traduction entre SQL et MongoDB, y compris les clauses OR. Cela peut être très utile pour déterminer la syntaxe lorsque vous connaissez l'équivalent SQL.

Dans le cas ou des déclarations, il semble que cette

SQL:

SELECT * FROM collection WHERE columnA = 3 OR columnB = 'string'; 

MongoDB:

db.collection.find({ 
    "$or": [{ 
     "columnA": 3 
    }, { 
     "columnB": "string" 
    }] 
});