2012-04-23 10 views
7

Próbowałem połączyć metody interfejsu (i) i() w interfejsie zapytania, aby utworzyć zestaw warunków, w których są 2 listy kryteriów i co najmniej jedna z nich muszą być spełnione.Złożone zapytanie AND-OR w Morphii

Przeczytałem i próbowałem użyć Query.and() do połączenia moich dwóch $ lub klauzul.

Zasadniczo, staram się powiedzieć:

Criteria[] arrayA; 
Criteria[] arrayB; 

// Programatically populate both arrays 

Query q = dao.createQuery().and(
    q.or(arrayA), 
    q.or(arrayB) 
); 

Używam tablice kryteriów, ponieważ mam do pętli przez kilka różnych wejść do generowania szczególne kryteria muszę, i to podejście działa, kiedy "Używam tylko jednego $ lub, ale nie mogę zmusić Morphii do wygenerowania zapytania, którego spodziewam się, gdy próbuję i zawieram zarówno $, jak i klauzule w $ i jak wyjaśniłem powyżej. Uważam, że nie ma żadnego $ i zapytania, a drugie $ lub nadpisało pierwsze, tak jakbym po prostu zadzwonił lub() dwa razy.

Np Spodziewam kwerenda być generowany tak:

{ 
    "$and": { 
    "0": { 
     "$or": { 
      "0": //Some criteria, 
      "1": //Some criteria, 
      "2": //Some criteria, 
     } 
    }, 
    "1": { 
     "$or": { 
      "0": //Some other criteria, 
      "1": //Some other criteria, 
      "2": //Some other criteria, 
     } 
    } 
} 

Jednak ja po prostu zapytać tak:

{ 
    "$or": { 
     "0": //Some other criteria, 
     "1": //Some other criteria, 
     "2": //Some other criteria, 
    } 
} 

nie mogę zobaczyć dużo dokumentacji, ale patrząc na przypadku testowego, wydaje się, że jest to właściwy sposób postępowania. Czy ktoś może rzucić jakiekolwiek światło na to, dlaczego to nie działa tak, jak oczekuję?

(To pytanie było cross-posted to the Morphia mailing list, jak nie jestem pewien, które miejsce byłoby uzyskać najlepszą odpowiedź)

Edycja 0:

Aktualizacja: Ponowne to, mam wyrejestrowany kodu testowego Morphia i wszystko działa dobrze, nie udało mi się odtworzyć mojego problemu w kodzie testowym.

Dlatego stworzyłem nowy projekt, aby spróbować uzyskać przykład wykonania żądanego zapytania. Jednak spotkałem się z tym samym problemem, nawet z projektem testowym barebone.

Projekt mavenised i POM jest:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
<modelVersion>4.0.0</modelVersion> 
<groupId>test</groupId> 
<artifactId>test</artifactId> 
<version>0.0.1-SNAPSHOT</version> 
<name>Test</name> 


<dependencies> 
    <dependency> 
     <groupId>com.google.code.morphia</groupId> 
     <artifactId>morphia</artifactId> 
     <version>0.99</version> 
    </dependency> 
</dependencies> 
<dependencyManagement> 
    <dependencies> 
     <!-- Force the use of the latest java mongoDB driver --> 
     <dependency> 
      <groupId>org.mongodb</groupId> 
      <artifactId>mongo-java-driver</artifactId> 
      <version>2.7.3</version> 
     </dependency> 
    </dependencies> 
</dependencyManagement> 

</project> 

Mam klasy TestEntity:

import java.util.Map; 

import com.google.code.morphia.annotations.Entity; 

@Entity 
public class TestEntity { 
    Map<String, Integer> map; 
} 

i wreszcie moją klasę testową:

import java.net.UnknownHostException; 
import java.util.HashMap; 
import java.util.Map; 

import com.google.code.morphia.Datastore; 
import com.google.code.morphia.Morphia; 
import com.google.code.morphia.query.Query; 
import com.google.code.morphia.query.QueryImpl; 
import com.mongodb.Mongo; 
import com.mongodb.MongoException; 

public class Test { 

    static Mongo mongo; 
    static Morphia m; 
    static Datastore ds; 

    static { 
     mongo = null; 
     try { 
      mongo = new Mongo(); 
     } catch (UnknownHostException e) { 
      e.printStackTrace(); 
     } catch (MongoException e) { 
      e.printStackTrace(); 
     } 
     m = new Morphia(); 
     ds = m.createDatastore(mongo, "test"); 
    } 

    public static void main(String[] args) { 
     populate(); 
     query(); 
    } 

    public static void query() { 
     Query<TestEntity> q = ds.createQuery(TestEntity.class); 

     q.and(q.or(q.criteria("map.field1").exists()), 
       q.or(q.criteria("map.field2").exists())); 

     Iterable<TestEntity> i = q.fetch(); 
     for (TestEntity e : i) { 
      System.out.println("Result= " + e.map); 
     } 

     QueryImpl<TestEntity> qi = (QueryImpl<TestEntity>) q; 
     System.out  
       .println("Query= " +   qi.prepareCursor().getQuery().toString()); 
    } 

    public static void populate() { 
     TestEntity e = new TestEntity(); 
     Map<String, Integer> map = new HashMap<String, Integer>(); 
     map.put("field1", 1); 
     map.put("field2", 2); 
     e.map = map; 

     ds.save(e); 
    } 
} 

dla mnie, powyższy kod nie generuje prawidłowych $ i zapytania, ale nie rozumiem, dlaczego

Odpowiedz

6

Pomimo Morphia 0.99 włącznie Metoda Query.and(Criteria ...) nie generuje poprawnego zapytania.

Issue 338, która dotyczy wsparcia dla wyraźnych dolarów i klauzul zapytaniami skierowany jest do morfiny 0.99.1, która jest obecnie dostępna tylko w wersji SNAPSHOT poprzez Maven.

Jednak użycie wersji 0.99.1-SNAPSHOT rozwiązało problem.

+1

- byłoby miło dać ostateczny, działający przykład. –

+0

Hi @RussBateman, kod się nie zmienił, wydaje się, że jest problem w wersji 0.99, który został rozwiązany w wersji 0.99.1-SNAPSHOT, więc po prostu zmieniliśmy wersję biblioteki, której używamy (nie jest idealna, ale najlepsza opcja, jaką mieliśmy) – chrisbunney

+0

Nawet z wersją 0.99.1-SNAPSHOT nadal mam problem z Query.and(). Jest to w porządku, o ile kryteria są prostymi polami, ale jeśli masz $ lub kryterium zawarte w $ i, to się nie powiedzie –

7

tylko zgadywać (nie mają czasu, aby przetestować), ale powinno być:

Query q = dao.createQuery().and(
    q.or(q.criteria(arrayA)), 
    q.or(q.criteria(arrayB)) 
); 

Aktualizacja Masz rację, Query.criteria nie miał rację - to było to, co zostało wykorzystane w prosty test , więc pomyślałem, że coś przeoczyłeś.To wydaje się działać dla mnie (łamiąc go na dwa sprawozdania):

Query q = dao.createQuery(); 
q.and(
    q.or(arrayA), 
    q.or(arrayB) 
); 

Aktualizacja 2 Więcej kompletny kod testowy:

Criteria[] arrayA = {dao.createQuery().criteria("test").equal(1), dao.createQuery().criteria("test").equal(3)}; 
Criteria[] arrayB = {dao.createQuery().criteria("test").equal(2), dao.createQuery().criteria("test").equal(4)};; 
Query q = dao.createQuery(); 
q.and(
    q.or(arrayA), 
    q.or(arrayB) 
); 
System.out.println(q.toString()); 

daje:

{ "$and" : [ { "$or" : [ { "test" : 1} , { "test" : 3}]} , { "$or" : [ { "test" : 2} , { "test" : 4}]}]} 
+0

Niestety nie, ponieważ 'Query.criteria()' przyjmuje jedynie ciąg znaków (który jest nazwą pola), a obie tablice są listami obiektów 'Criteria'. Nie ma alternatywnych metod do użycia, a ponieważ przejście przez tablice pracowało nad skonstruowaniem pojedynczego lub klauzuli, może zajść potrzeba sprawdzenia kodu morfologicznego i napisania przypadku testowego dla tego scenariusza. – chrisbunney

+0

Zaktualizowano lepszą odpowiedzią. Mam nadzieję, że to działa dla ciebie. –

+0

Dzięki za aktualizację, to interesujące, więc to działa tak dla Ciebie? Moje aktualne zapytanie jest bardziej skomplikowane niż prosty przykład, który dałem, aby zilustrować moją intencję, ale założyłem, że zasada była rozsądna. Być może problem jest gdzieś indziej w kodzie zapytania i jest to tylko objaw ... – chrisbunney

Powiązane problemy