I have three classes in my Java project:
@Document(collection = "foos")
public class Foo {
@Id
private String id;
private String foo_name;
private Set<Bar> bars;
}
@Document(collection = "bazs")
public class Baz {
@Id
private String id;
private String baz_name;
}
public class Bar {
@DBRef
private Baz baz;
private String bar_name;
}
Then, I have /foo
POST endpoint that accepts the body of a foo and stores it in a database.
@PostMapping
public Foo addFoo(@RequestBody Foo foo) {
return repository.save(foo);
}
Given a Baz
already stored in mongoDB with the id = ObjectId('62b795ea78aa537285762a1f')
and name = the baz name
, and I can call the /foo
endpoint with the following body:
{ "foo_name" = "the foo name", "bars"= ["baz"= { "id" = "62b795ea78aa537285762a1f" }, "bar_name" = "the bar name"] }
I get a 200 OK, but the response looks like this:
{ "id" = "62b6e461cf1993ef423a28b3", "foo_name" = "the foo name", "bars"= ["baz"= { "id" = "62b795ea78aa537285762a1f", "baz_name" = null } , "bar_name" = "the bar name"]
If I use the GET endpoint /foo/62b6e461cf1993ef423a28b3
, I do get all the @DBRef info:
{ "id" = "62b6e461cf1993ef423a28b3", "foo_name" = "the foo name", "bars"= ["baz"= { "id" = "62b795ea78aa537285762a1f", "baz_name" = "the baz name" } , "bar_name" = "the bar name"]
Note the difference in the baz_name
variable.
How can I make my code return all the data once I save a new item foo? Or, at least, don’t send null values that are not real
2
Answers
If you check source code of
save
method:What it does is to check if this entity on which you called save is new one or existing. If entity is existing entity — which is the case for you, then it call
merge
rather thanpersist
.Now, what actually happens in merge is it merge & returns the managed instance that the state was merged with. What it means is it either returns entity which exists PersistenceContext or creates a new instance all along.
In any case, it will copy the state from the supplied entity, and return a managed copy. What it means in database terminology is it does
upsert
(INSERT or UPDATE) scenario.Meaning, it will insert if its new or update if its existing. Now in your case, since its already present entity, so it does update.
In update case, the details which got updated are returned & other fields which didn’t get updated are not returned. Means in your case, except
bar_name
everything else got updated in database againstid = ObjectId('62b795ea78aa537285762a1f')
as that’s what you supplied in your input to save.Once update successful, it returned what got updated & not end result & that is reason you will see
bar_name
as null when you directly doreturn repository.save(foo);
for existing record.If you really want to return full entity & not what got updated in database, you must do something like (provided your input will not necessarily containing all fields of entity) :
Further read : http://spitballer.blogspot.com/2010/04/jpa-persisting-vs-merging-entites.html
The main question would be how you would describe the relationships between Bar and Foo.
You seem to be treat it like a ManyToOne but the reference is store on Bar like a foreigh key in a relational database.
Bar points to Foo implies the Foo is the owner and therefore you could annotated Foo having @DBRef Set bars.
If the relationship is bidirectional you need to annotate both sides.