2012-10-04 15 views
11

Ich habe zwei Domain-Objekte,Federdaten - MongoDB - findBy Methode für verschachtelte Objekte

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

Mein JSON doc ist wie diese,

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

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

Ich habe den "Typ" auf der Grundlage aktualisieren auf userId und QuestionID, so habe ich eine findBy Abfragemethode innerhalb der benutzerdefinierten Repository-Schnittstelle geschrieben,

public interface CustomRepository extends MongoRepository<PracticeQuestion, String> { 

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

Mein Problem ist, Wenn ich diese Methode mit userId als 1 und questionID als 3 ausfühle, wird die gesamte Fragenliste unabhängig von der FrageID zurückgegeben. Ist der Name der Abfragemethode gültig oder wie schreibe ich die Abfrage für verschachtelte Objekte?

Danke für jeden Vorschlag.

Antwort

14

Verwenden Sie einfach die @Query Annotation für diese Methode.

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

} 

den fields Teil der @Query Anmerkung Durch das Hinzufügen Sie Mongo sagen Rückkehr nur, dass ein Teil des Dokuments. Beachten Sie jedoch, dass es immer noch das gesamte Dokument im selben Format zurückgibt - es fehlt nur alles, was Sie nicht angegeben haben. So Ihr Code muss noch List<PracticeQuestion> zurückkehren und Sie tun müssen:

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

Dank für Sie antworten, aber auch hier diese Abfrage gibt eine Array und nicht das entsprechende Element im Array. – user1720083

+1

Oh. Ich verstehe was du meinst. Sie können immer nur das gesamte Dokument zurückgeben. Die Abfrage sucht tatsächlich nach Dokumenten mit dieser Frage-ID. Aber Sie bekommen immer das gesamte Dokument zurück - nie nur die Frage. Es ist keine Java-Sache, es ist eine MongoDB-Sache.Schauen Sie sich diese Frage/Antwort zur Klärung an: http://StackOverflow.com/a/3985982/229178 – sbzoom

+1

Nach einigen Hausaufgaben wurde mir klar, dass Sie Teilobjekte im 'fields' Teil Ihrer Anfrage (' Projektionen') angeben können. http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields Ich werde meine obige Antwort aktualisieren, um ein Beispiel zu geben. – sbzoom

5

Eigenschaftsausdrücken

Property Ausdrücke nur auf eine direkte Eigenschaft der verwalteten Einheit beziehen, wie im obigen Beispiel gezeigt. Zum Zeitpunkt der Abfrageerstellung stellen Sie bereits sicher, dass die analysierte Eigenschaft eine Eigenschaft der verwalteten Domänenklasse ist. Sie können Einschränkungen jedoch auch definieren, indem Sie verschachtelte Eigenschaften durchlaufen. Angenommen, Personen haben Adressen mit ZipCodes. In diesem Fall wird ein Methodenname

Liste findByAddressZipCode (ZipCode zipCode); erstellt die Eigenschaft traversal x.address.zipCode. Der Auflösungsalgorithmus beginnt mit der Interpretation des gesamten Teils (AddressZipCode) als Eigenschaft und überprüft die Domänenklasse für eine Eigenschaft mit diesem Namen (nicht in Großbuchstaben). Wenn der Algorithmus erfolgreich ist, verwendet er diese Eigenschaft. Wenn nicht, teilt der Algorithmus die Quelle an den Kamelfallteilen von der rechten Seite in einen Kopf und einen Schwanz auf und versucht, die entsprechende Eigenschaft zu finden, in unserem Beispiel AddressZip und Code. Wenn der Algorithmus eine Eigenschaft mit diesem Kopf findet, nimmt er den Schwanz und baut den Baum weiter von dort auf, indem er den Schwanz auf die beschriebene Weise aufteilt. Wenn der erste Split nicht übereinstimmt, verschiebt der Algorithmus den Splitpunkt nach links (Address, ZipCode) und fährt fort.

Obwohl dies in den meisten Fällen funktionieren sollte, ist es möglich, dass der Algorithmus die falsche Eigenschaft auswählt. Angenommen, die Person-Klasse hat auch eine addressZip-Eigenschaft. Der Algorithmus würde bereits in der ersten Zwischenzeitrunde übereinstimmen und im Wesentlichen die falsche Eigenschaft auswählen und schließlich fehlschlagen (da der Typ von addressZip wahrscheinlich keine Codeeigenschaft hat). Um diese Mehrdeutigkeit zu beheben, können Sie _ innerhalb Ihres Methodennamens verwenden, um Traversalpunkte manuell zu definieren.So würde unsere Methode Namen alle wie so enden:

UserDataRepository:

Liste findByAddress_ZipCode (ZipCode zipCode);

UserData findByUserId (Zeichenfolge userId);

ProfileRepository:

Profil findByProfileId (String des Profil);

UserDataRepositoryImpl:

Userdata Userdata = userDateRepository.findByUserId (userId);

Profilprofil = profileRepository.findByProfileId (userData.getProfileId());

userData.setProfile (Profil);

Probe 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 Profil {

private String email; 
private String profileId; 

}

Für das oben genannte Dokument/POJO in Ihrer Repository-Klasse:

UserData findByProfile_Email (String email);

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

0

Sie benötigen Rahmen Mongo Aggregation verwenden:

1) Erstellen Sie benutzerdefinierte Methode für Mongo-Repository: 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) Sie müssen eine Klasse cretae (Da der Abwicklungsvorgang die Klassenstruktur geändert hat) wie folgt:

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

Dies wird Ihnen nur diejenigen Ergebnis, das die

Ergebnis für userId userId und questionId Spiele bieten: 1 und QuestionID: 111:

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