19

I am having trouble writing code that would allow get a user and claim details in a straightforward way. This is my MongoDB structure,

db.user.find();
user: 
    {
    "name" : "KSK", 
     "claim"  : [objectId("52ffc4a5d85242602e000000"),objectId("52ffc4a5d85242602e000001")] 
    }

claim: 

    [
       {
         "_id" : "52ffc4a5d85242602e000001",
         "claimName" :"XXXX"
       },
       {
         "_id" : "52ffc4a5d85242602e000000",
         "claimName" :"YYY"
       }
    ]

My Entity class is:

@Document(collection="user")
public  class User{
    @Id      
    private String id;
    private String name; 
    @DBRef
    private List<Claim> claim; 
    // setter and getter   
}

Claim Class:

@Document(collection="Claim")
public class Claim{
    @Id 
    private String id; 
    private String claimName;   
}

I have a method to get the users by name like below,

public User findByName(String name);

If I try to hit this method am getting an error that,

No converter found capable of converting from type org.bson.types.ObjectId to type java.lang.String

So I changed my User entity class as like below,

Instead of private List<Claim> claim;

Changed as Private List<ObjectId> claim;

Now if I execute a method(findByName), I get a user object that has both claimed object ids ("52ffc4a5d85242602e000001","52ffc4a5d85242602e000000"), then iterate the claim list and get the claim details corresponding to the claim object Id.

Instead of doing this, when I execute findByName method I want to get a user and claim details. How can I achieve this functionality?

sashimi
  • 1,224
  • 2
  • 15
  • 23
KSK
  • 636
  • 1
  • 9
  • 29
  • Your initial approach with List looks alright. Are you sure it isn't a camel case issue, see ``claimname`` in your Java class and ``claimName`` in your JSON. – Jan B. May 30 '17 at 20:01
  • @Matt it just a typo error. I modified now. – KSK May 31 '17 at 07:14

3 Answers3

15

If you reference your Claims in the User class with @DBRef, your JSON should not only contain the ID but the reference to the collection where to find the ID as well, like this:

{
  "name" : "KSK", 
  "claim" : [ 
     { 
       "$ref" : "claim", // the target collection
       "$id" : ObjectId("52ffc4a5d85242602e000000")
     }
  ] 
}

That is how Spring-Data maps your Java objects to MongoDB. If you start with a blank database and let Spring create and save the relations, you should have no problems using

 @DBRef List<Claim> claims;
Jan B.
  • 6,030
  • 5
  • 32
  • 53
2

My suggestion is not to set that Claim class into separate @Document or just switch back to Relational Databases, because it's not a Mongo approach. Also, if you insist on current architecture you can try using @DBRef above that List in User.class into smth like this:

public class ParentModel {

    @Id
    private String id;

    private String name;

    private ParentType parentType;

    private SubType subType;

    @DBRef
    private List<Model> models;

....
}
Kohei TAMURA
  • 4,970
  • 7
  • 25
  • 49
Andrew Petryk
  • 229
  • 2
  • 4
  • I missed out to add DBRef in my post. Now I have edited it. Please look at now. As you suggested if I go with embedded relationship, if the embedded document keeps on growing too much in size, it can impact the read/write performance. That's why I decided to go with reference relationship. – KSK May 30 '17 at 12:18
  • you will exceed 16 mb? That should be a huge document. If you managed to get User with List i do not really understand what you want above this? Mb if you explain it more clearly I will try to help – Andrew Petryk May 30 '17 at 13:05
  • If I add DBRef private ListI am getting an error. I have mentioned the error in my post. What I need is, when I call a findByName then I want a user and corresponding to the claims details. – KSK May 30 '17 at 13:44
  • did you generate getters and setters?you can use Lombok for that purpose – Andrew Petryk May 30 '17 at 14:39
0

as an alternative to @DBRef, take a look at RelMongo (link) which provides a powerfull way to manage relations, in your case it will be like this :

@OneToMany(fetch = FetchType.LAZY)
private list<Claim> claims;
Chin
  • 9
  • 1