dbaer
dbaer

Reputation: 1316

id attribute in nested Java class mapped as MongoDb ObjectId()

Following structure:

@Document 
public class Palace {
    @Id
    private String id;
    private Location location;
    // additional attributes, getter, setter 
}

.

public class Location {
    private String id;
    // additional attributes, getter, setter
}

As far as I understand the concept of ObjectId, there can be only one ObjectId (_id) in a MongoDB document and it must be at the root level of the document. But when inserting data via Spring Boot 1.5.14 I get the followng structure:

{
    "_id" : ObjectId("5b05387a8db58e0001d38851"),
    "location" : {
        "_id" : ObjectId("5ae712d1b2b197000132cd9b"),
    }
}

My question is: Is this the expected behaviour in spring-data-mongo? I would have expected the following structure:

{
    "_id" : ObjectId("5b05387a8db58e0001d38851"),
    "location" : {
        "id" : "5ae712d1b2b197000132cd9b",
    }
}

If I annotate the Location id with @Field

public class Location {
    @Field("id")
    private String id;
    // additional attributes, getter, setter
}

then the Document is saved as expected, but querying with repository method

getPalaceByLocationId()

won't give any results.

Upvotes: 2

Views: 2773

Answers (1)

pvpkiran
pvpkiran

Reputation: 27018

Some insights into id field. id field is treated a bit differently in spring-data-mongodb.

Check out the documentation.

Extending the documentation for your case, when you declare an id like this

public class Location {
    private String id;
    // additional attributes, getter, setter
}

It is stored as _id in database. You can cross check by looking into the database. The same is true when you annotate it with @Id

{
    "_id" : ObjectId("5b31fad36a19cc45db205056"),
    "location" : {
        "_id" :  ObjectId("5ae712d1b2b197000132cd9b")
    }
}

5ae712d1b2b197000132cd9b is the id you had set using location.setId(). Internally it is converted to ObjectId and stored as _id.

But when you add @Field annotation, things change. Let's assume you add an annotation like this

@Field("id")
private String id;

Then the document looks like this in database.

{
    "_id" : ObjectId("5b31fad36a19cc45db205056"),
    "location" : {
        "id" :  "5ae712d1b2b197000132cd9b"
    }
}

With this the problem is you cannot retrieve by id. Because when you write findPalaceByLocationId or findByLocation_Id it(spring-data) tries to look for _id field which doesn't exist.

Only way around this is just use it like this

@Field
private String id;

or just

private String id;

This will create _id in database and you can do findByLocationId

I know it is a bit sketchy. But that is how it works.

And regarding

As far as I understand the concept of ObjectId, there can be only one ObjectId (_id) in a MongoDB document and it must be at the root level of the document.

that is incorrect.

A small info table regarding mapping

Field definition         Resulting Id-Fieldname in MongoDB  

String id                      _id  
@Field String id               _id  
@Field('x') String id           x    
@Field('id') String id          id (InAccessible)   
@Id String x                   _id  
@Field('x') @Id String x       _id 

Upvotes: 1

Related Questions