2012-10-04 29 views
11

Tengo dos objetos de dominio,primavera - MongoDB - Método findBy de objetos anidados

@Document 
public class PracticeQuestion { 

    private int userId; 
    private List<Question> questions; 

// Getters and setters 
} 

@Document 
public class Question { 

    private int questionID; 
    private String type; 

// Getters and setters 
} 

Mi doctor JSON es así,

{ 
    "_id" : ObjectId("506d9c0ce4b005cb478c2e97"), 
    "userId" : 1, 
    "questions" : [ 
     { 
      "questionID" : 1, 
      "type" : "optional" 

     }, 
     { 
      "questionID" : 3, 
      "type" : "mandatory" 
     } 
    ] 
} 

tengo que actualizar el "tipo", basada en ID de usuario y IdPregunta, por lo que he escrito un método de consulta findBy dentro de la interfaz de repositorio personalizado,

public interface CustomRepository extends MongoRepository<PracticeQuestion, String> { 

    List<PracticeQuestion> findByUserIdAndQuestionsQuestionID(int userId,int questionID);  
} 

Mi problema es cuando ejecuto este método con userId como 1 y questionID como 3, devuelve la lista de preguntas completa independientemente del questionID. Es el nombre del método de consulta válido o cómo debo escribir la consulta para los objetos anidados.

Gracias por cualquier sugerencia.

Respuesta

14

Simplemente use la anotación @Query en ese método.

public interface CustomRepository extends MongoRepository<PracticeQuestion, String> { 

    @Query(value = "{ 'userId' : ?0, 'questions.questionID' : ?1 }", fields = "{ 'questions.questionID' : 1 }") 
    List<PracticeQuestion> findByUserIdAndQuestionsQuestionID(int userId, int questionID); 

} 

Mediante la adición de la parte fields del @Query anotación, le está diciendo Mongo sólo para regresar esa parte del documento. Sin embargo, tenga cuidado, todavía devuelve todo el documento en el mismo formato, simplemente omitiendo todo lo que no especificó. Así que el código todavía tendrá que volver List<PracticeQuestion> y usted tendrá que hacer:

foreach (PracticeQuestion pq : practiceQuestions) { 
    Question q = pq.getQuestions().get(0); // This should be your question. 
} 
+0

Gracias por su respuesta, pero de nuevo esta consulta devuelve una matriz en lugar del elemento apropiado en la matriz. – user1720083

+1

Oh. Veo a que te refieres. Solo puede devolver el documento completo. La consulta realmente busca documentos que tengan ese questionID. Pero siempre obtienes todo el documento devuelto, nunca solo la pregunta. No es una cosa de Java, es una cosa de MongoDB.Mire esta pregunta/respuesta para aclarar: http://stackoverflow.com/a/3985982/229178 – sbzoom

+1

Después de algunas tareas, me di cuenta de que puede especificar objetos parciales en la parte 'campos' de su consulta (' proyecciones'). http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields Actualizaré mi respuesta anterior para dar un ejemplo. – sbzoom

5

expresiones de propiedad

expresiones de propiedades sólo pueden referirse a una propiedad directa de la entidad gestionada, como se muestra en el ejemplo anterior. En el momento de la creación de la consulta, usted ya se asegura de que la propiedad analizada sea propiedad de la clase de dominio administrado. Sin embargo, también puede definir restricciones atravesando propiedades anidadas. Supongamos que las personas tienen direcciones con ZipCodes. En ese caso, un nombre de método de

Lista findByAddressZipCode (ZipCode zipCode); crea la propiedad transversal x.address.zipCode. El algoritmo de resolución comienza con la interpretación de la parte completa (AddressZipCode) como propiedad y verifica la clase de dominio para una propiedad con ese nombre (sin capitalizar). Si el algoritmo tiene éxito, usa esa propiedad. Si no, el algoritmo divide la fuente en las partes de la caja del camello del lado derecho en una cabeza y una cola e intenta encontrar la propiedad correspondiente, en nuestro ejemplo, AddressZip y Code. Si el algoritmo encuentra una propiedad con esa cabeza, toma la cola y continúa construyendo el árbol desde allí, dividiendo la cola en la forma que acabamos de describir. Si la primera división no coincide, el algoritmo mueve el punto de división hacia la izquierda (Dirección, Código postal) y continúa.

Aunque esto debería funcionar para la mayoría de los casos, es posible que el algoritmo seleccione la propiedad incorrecta. Supongamos que la clase Person también tiene una propiedad addressZip. El algoritmo coincidiría ya en la primera ronda dividida y esencialmente elegiría la propiedad incorrecta y finalmente fallaría (ya que el tipo de addressZip probablemente no tiene propiedad de código). Para resolver esta ambigüedad, puede usar _ dentro de su nombre de método para definir manualmente los puntos de cruce.Por lo que nuestro nombre de método terminaría de esta manera:

UserDataRepository:

Lista findByAddress_ZipCode (ZipCode código postal);

UserData findByUserId (String userId);

ProfileRepository:

Perfil findByProfileId (String profileId);

UserDataRepositoryImpl:

UserData userData = userDateRepository.findByUserId (userId);

Profile profile = profileRepository.findByProfileId (userData.getProfileId());

userData.setProfile (perfil);

Pojo muestra:

clase pública UserData {

private String userId; 
private String status; 
private Address address; 
private String profileId; 

//New Property 
private Profile profile; 

//TODO:setter & getter 

}

public class {Perfil

private String email; 
private String profileId; 

}

Para el documento/POJO anterior en su Clase de repositorio:

UserData findByProfile_Email (String email);

Por ref: http://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html

0

Es necesario utilizar marco Mongo Agregación:

1) Crear método personalizado para el repositorio de mongo: Add custom method to Repository

UnwindOperation unwind = Aggregation.unwind("questions"); 
MatchOperation match = Aggregation.match(Criteria.where("userId").is(userId).and("questions.questionId").is(questionID)); 
Aggregation aggregation = Aggregation.newAggregation(unwind,match); 
AggregationResults<PracticeQuestionUnwind> results = mongoOperations.aggregate(aggregation, "PracticeQuestion", 
       PracticeQuestionUnwind.class); 
return results.getMappedResults(); 

2) Es necesario cretae una clase (Debido a que la operación de desenrollado ha cambiado la estructura de clase) como se muestra a continuación:

public class PracticeQuestionUnwind { 
    private String userId; 
    private Question questions; 

esto le dará sólo aquellos resultado que coincide con la proporcionan userId y questionId

Resultado de ID de usuario: 1 y IdPregunta: 111:

{ 
    "userId": "1", 
    "questions": { 
       "questionId": "111", 
       "type": "optional" 
      } 
} 
Cuestiones relacionadas