2012-04-23 36 views
7

He estado tratando de combinar los métodos y() y o() de la interfaz de Consulta para crear un conjunto de condiciones donde hay 2 listas de criterios, y al menos uno de cada debe estar satisfechoCompleja AND-OR consulta en Morphia

He leído this discussion y he estado tratando de usar el Query.and() para combinar mis dos $ o cláusulas.

En esencia, yo estoy tratando de decir:

Criteria[] arrayA; 
Criteria[] arrayB; 

// Programatically populate both arrays 

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

estoy usando matrices de criterios porque tengo que recorrer varias entradas diferentes para generar los criterios particulares que necesito, y este enfoque funciona cuando Estoy usando solo $ o, pero no puedo hacer que Morphia genere la consulta que espero cuando intento incluir $ o cláusulas en $ y como expliqué anteriormente. Me parece que no hay $ y la consulta y el segundo $ o ha sobrescrito el primero, como si simplemente hubiera llamado o() dos veces.

EG I espera una consulta que se genera de esta manera:

{ 
    "$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, 
     } 
    } 
} 

Sin embargo, acabo de recibir una consulta como esta:

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

no puedo ver mucha documentación, pero mirando el caso de prueba, esta parece ser la forma correcta de hacerlo. ¿Alguien puede ayudar a arrojar alguna luz sobre por qué esto no está funcionando como espero?

(Esta pregunta fue cross-posted to the Morphia mailing list, ya que no estoy seguro de qué lugar sería obtener la mejor respuesta)

Editar 0:

actualización: Repaso a esto, he comprobado el código de prueba Morphia y todo funciona bien, no he podido reproducir mi problema en el código de prueba.

Por lo tanto, creé un nuevo proyecto para tratar de obtener un ejemplo de trabajo de la consulta que deseo. Sin embargo, me encontré con el mismo problema, incluso con un proyecto de prueba barebones.

El proyecto se mavenised y el POM es:

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

tengo una clase TestEntity:

import java.util.Map; 

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

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

Y por último, mi clase de prueba:

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

Para mí, el código anterior no produce los $ correctos y la consulta, pero no puedo ver por qué

Respuesta

6

pesar Morphia 0.99 incluida el método Query.and(Criteria ...), no genera la consulta correcta.

Issue 338, que se ocupa de soporte para explícitos $ y cláusulas de consultas está dirigido a Morphia 0.99.1, que actualmente sólo está disponible como una versión INSTANTÁNEA través de Maven.

Sin embargo, el uso de 0.99.1-SNAPSHOT resolvió el problema para nosotros.

+1

- habría sido bueno dar el último ejemplo de trabajo. –

+0

Hola @RussBateman, el código no cambió, parece que hay un problema en la versión 0.99 que se resuelve en 0.99.1-SNAPSHOT, así que simplemente cambiamos la versión de la biblioteca que estamos usando (no es ideal, pero el mejor opción que tuvimos) – chrisbunney

+0

Incluso con 0.99.1-SNAPSHOT todavía tengo el problema con Query.and(). Está bien siempre que los Criterios sean campos simples, pero cuando tiene $ o un criterio incluido en $ y, fallará –

7

sólo una suposición (no tienen tiempo para probar), pero en caso de que sea:

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

actualización Tienes razón, Query.criteria no estaba bien - que era lo que se utilizó en la prueba simple , así que pensé que te habías perdido algo.Esto parece funcionar para mí (dividiéndola en dos estados):

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

Actualización 2 más completa código de prueba:

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()); 

da:

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

Desafortunadamente no, ya que 'Query.criteria()' solo toma una cadena (que es el nombre del campo), y ambas matrices son listas de objetos 'Criteria'. No hay métodos alternativos para usar, y dado que al pasar los arreglos funcionó para construir una sola o una cláusula, es posible que necesite revisar el código de Morphia y escribir un caso de prueba para este escenario – chrisbunney

+0

Actualizado con una mejor respuesta. Espero que funcione para ti. –

+0

Gracias por la actualización, eso es interesante, ¿te funciona así? Mi consulta real es más complicada que el simple ejemplo que di para ilustrar mi intención, pero asumí que el principio era sólido. Tal vez el problema esté en otra parte del código de consulta y este es solo el síntoma ... – chrisbunney