2012-10-04 11 views
11

Ho due oggetti di dominio,primavera - MongoDB - Metodo findBy per gli oggetti nidificati

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

mio JSON doc è come questo,

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

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

devo aggiornare il "tipo" sulla base di userid e QuestionID, così ho scritto un metodo di query findBy all'interno dell'interfaccia repository personalizzati,

public interface CustomRepository extends MongoRepository<PracticeQuestion, String> { 

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

il mio problema è quando eseguo questo metodo con userId come 1 e questionID come 3, restituisce l'intero elenco di domande indipendentemente dal questionid. Il nome del metodo di query è valido o come dovrei scrivere la query per gli oggetti nidificati.

Grazie per qualsiasi suggerimento.

risposta

14

Basta usare l'annotazione @Query su tale metodo.

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

} 

Aggiungendo la parte fields del @Query di annotazione, si indica Mongo per restituire solo quella parte del documento. Attenzione però, restituisce comunque l'intero documento nello stesso formato, mancando semplicemente tutto ciò che non hai specificato. Così il vostro codice dovrà ancora tornare List<PracticeQuestion> e si dovrà fare:

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

Grazie per si risponde, ma ancora una volta questa query restituisce un array piuttosto che l'elemento appropriato nell'array. – user1720083

+1

Oh. Capisco cosa intendi. Puoi sempre restituire l'intero documento. La query cerca effettivamente i documenti che hanno quel questionid. Ma ottieni sempre l'intero documento restituito - mai solo la domanda. Non è una cosa java, è una cosa di MongoDB.Guarda questa domanda/risposta per chiarimenti: http://stackoverflow.com/a/3985982/229178 – sbzoom

+1

Dopo alcuni compiti mi sono reso conto che puoi specificare oggetti parziali nella parte 'fields' della tua query (' proiezioni '). http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields aggiornerò la mia risposta sopra per dare un esempio. – sbzoom

5

espressioni di proprietà

espressioni di proprietà possono riferirsi soltanto a una proprietà diretta della entità gestita, come mostrato nell'esempio precedente. Al momento della creazione della query ci si assicura già che la proprietà analizzata sia una proprietà della classe del dominio gestito. Tuttavia, è anche possibile definire i vincoli attraversando le proprietà annidate. Supponiamo che le persone abbiano indirizzi con codici postali. In tal caso, il nome del metodo

Elenco findByAddressZipCode (ZipCode zipCode); crea la proprietà traversal x.address.zipCode. L'algoritmo di risoluzione inizia con l'interpretazione dell'intera parte (AddressZipCode) come proprietà e controlla la classe di dominio per una proprietà con quel nome (nonapitalizzata). Se l'algoritmo ha successo, usa quella proprietà. In caso contrario, l'algoritmo divide la sorgente delle parti del caso cammello dal lato destro in una testa e una coda e cerca di trovare la proprietà corrispondente, nel nostro esempio AddressZip e Codice. Se l'algoritmo trova una proprietà con quella testa, prende la coda e continua a costruire l'albero da lì, dividendo la coda nella maniera appena descritta. Se la prima divisione non corrisponde, l'algoritmo sposta il punto di divisione a sinistra (Indirizzo, Codice postale) e continua.

Sebbene questo dovrebbe funzionare per la maggior parte dei casi, è possibile che l'algoritmo selezioni la proprietà errata. Supponiamo che la classe Person abbia anche una proprietà addressZip. L'algoritmo corrisponderebbe già al primo turno di suddivisione e in sostanza sceglierà la proprietà sbagliata e infine fallirà (poiché il tipo di indirizzoZip probabilmente non ha alcuna proprietà di codice). Per risolvere questa ambiguità puoi usare _ all'interno del nome del tuo metodo per definire manualmente i punti di attraversamento.Così il nostro nome del metodo finirebbe in questo modo:

UserDataRepository:

Lista findByAddress_ZipCode (ZipCode codice postale);

UserData findByUserId (String userId);

ProfileRepository:

Profilo findByProfileId (String ProfileId);

UserDataRepositoryImpl:

UserData userData = userDateRepository.findByUserId (userId);

Profilo profilo = profiloRepository.findByProfileId (userData.getProfileId());

userData.setProfile (profilo);

Esempio Pojo:

public class UserData {

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

//New Property 
private Profile profile; 

//TODO:setter & getter 

}

public class Profilo {

private String email; 
private String profileId; 

}

Per il documento/POJO sopra riportato nella classe del repository:

UserData findByProfile_Email (String email);

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

0

è necessario utilizzare Mongo aggregazione quadro:

1) Creare metodo personalizzato per repository 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) È necessario cretae una classe (Poiché l'operazione di svolgimento ha modificato la struttura della classe) come di seguito:

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

Questo vi darà solo quelli risultato che corrisponde alla forniscono userId e questionId

Risultato per l'utente id: 1 e QuestionID: 111:

{ 
    "userId": "1", 
    "questions": { 
       "questionId": "111", 
       "type": "optional" 
      } 
} 
Problemi correlati