I tried to return the entity directly as response resulted in error as "Could not write JSON: Infinite recursion (StackOverflowError)", I would like to get the response in both forms with out transforming the data. Can some one suggest work around. Adding the Entity structure for your reference.
Employee Entity
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long employeeId;
private String firstName;
private String lastName;
private String role;
#OneToMany(mappedBy = "employee")
private Set<EmployeeStream> streams = new HashSet<>();
}
Stream Entity
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Stream {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long streamId;
private String streamName;
#OneToMany(mappedBy = "stream")
private Set<EmployeeStream> employees = new HashSet<>();
}
EmployeeStream Entity with additional Attribute experience
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class EmployeeStream {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "EMPLPOYEE_ID")
private Employee employee;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "STREAM_ID")
private Stream stream;
private double experience;
}
I would like to retrieve data in both forms
{
"employeeId": 1,
"firstName": "George",
"lastName": "Stephen",
"role": "developer",
"streams": [
{
"id": 1,
"stream": {
"streamId": 1,
"streamName": "Java"
},
"experience": 1.2
},
{
"id": 2,
"stream": {
"streamId": 2,
"streamName": "Node JS"
},
"experience": 2
}
]
}
{
"stream": {
"streamId": 1,
"streamName": "Java",
"employees": [
{
"id": 1,
"employee": {
"employeeId": 1,
"firstName": "George",
"lastName": "Stephen",
"role": "developer"
},
"experience": 2
},
{
"id": 2,
"employee": {
"employeeId": 1,
"firstName": "Davis",
"lastName": "Tom",
"role": "developer"
},
"experience": 0.5
}
]
}
}
You need to use #JsonBackReference and #JsonManagedReference as used in the below in below code.
Employee entity
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long employeeId;
private String firstName;
private String lastName;
private String role;
#OneToMany(mappedBy = "employee")
#JsonManagedReference
private Set<EmployeeStream> streams = new HashSet<>();
}
Stream entity
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Stream {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long streamId;
private String streamName;
#OneToMany(mappedBy = "stream")
#JsonManagedReference
private Set<EmployeeStream> employees = new HashSet<>();
}
EmployeeStream entity
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class EmployeeStream {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "EMPLPOYEE_ID")
#JsonBackReference
private Employee employee;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "STREAM_ID")
#JsonBackReference
private Stream stream;
private double experience;
}
You can find more details here and here
Update: Previously #JsonBackReference and #JsonManagedReference was misplaced, corrected the same.
Note: If still faced any problem then try removing #JsonManagedReference from Stream and Employee entities.
Related
I'm developing a spring boot application. I've 2 models that is
PersonEntity
#Data
#Document(collection = "products")
public class ProductEntity implements Serializable {
private static final long serialVersionUID = -8118791879505582652L;
#MongoId(FieldType.STRING)
private String id;
#Indexed
#Field("name")
private String name;
#Field("category")
#DBRef(lazy = true)
private CategoryEntity category;
// getters and setters
}
CategoryEntity
#Data
#Document(collection = "categories")
public class CategoryEntity implements Serializable {
private static final long serialVersionUID = -636356399519451958L;
#MongoId(value = FieldType.STRING)
private String id;
#Field("name")
private String name;
#Field("desc")
private String desc;
public CategoryEntity(String id) {
super();
this.id = id;
}
// getters and setters
}
when I'm saving data into DB then stored data is
Products Document
{
"_id": {
"$oid": "6141eeab92432109463ae8c4"
},
"name": "Adidas Running Shoes",
"category": {
"$ref": "categories",
"$id": "614049d91042cf40b5b9b304"
}
}
Categories Document
{
"_id": {
"$oid": "614049d91042cf40b5b9b304"
},
"name": "Shoes",
"desc": "Men's running Shoes",
}
But when I'm try to findAll() the ProductEntity the data by using Spring-Data-MongoDB the category will return null.
public List<ProductModel> getProducts() {
List<ProductEntity> entities = productRepo.findAll();
return entities.stream().map(entity -> {
ProductModel product = new ProductModel();
BeanUtils.copyProperties(entity, product);
if (Objects.nonNull(entity.getCategory())) {
BeanUtils.copyProperties(entity.getCategory(), product.getCategory());
}
return product;
}).collect(Collectors.toList());
}
and I need the output will be in below format.
{
"_id": {
"$oid": "6141eeab92432109463ae8c4"
},
"name": "Adidas Running Shoes",
"category": {
"_id": {
"$oid": "614049d91042cf40b5b9b304"
},
"name": "Shoes",
"desc": "Men's running Shoes",
}
}
Please let me know how to get desired output.
I've done a minor change and issue has been resolved. I've changed
from
#MongoId(value = FieldType.STRING)
private String id;
to
#MongoId(value = FieldType.OBJECT_ID)
private ObjectId id;
in the both entities and code works!
This is City document class which i used.
#Document("city")
public class City {
#Id
private String id;
#Indexed(unique = true)
private String name;
#DBRef(lazy = true)
private District district;
public City() {
}
public City(String id) {
this.id = id;
}
public City(String id, String name, District district) {
this.id = id;
this.name = name;
this.district = district;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public District getDistrict() {
return district;
}
public void setDistrict(District district) {
this.district = district;
}
}
and this is the District document class
#Document("district")
public class District {
#Id
private String id;
#Indexed
private String name;
public District() {
}
public District(String id) {
this.id = id;
}
public District(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
and this is the district collection data.
/* 1 */
{
"_id" : ObjectId("5d9482f3ff7ab743f0542070"),
"name" : "Ampara",
"_class" : "com.test.sample.model.District"
}
/* 2 */
{
"_id" : ObjectId("5d9482f3ff7ab743f0542071"),
"name" : "Anuradhapura",
"_class" : "com.test.sample.model.District"
}
and this is the city collection data.
/* 1 */
{
"_id" : ObjectId("5d948333ff7ab743f0542089"),
"name" : "Polgampola",
"district" : {
"$ref" : "district",
"$id" : ObjectId("5d9482f3ff7ab743f0542070")
},
"_class" : "com.test.sample.model.City"
}
/* 2 */
{
"_id" : ObjectId("5d948333ff7ab743f054208a"),
"name" : "Porawagama",
"district" : {
"$ref" : "district",
"$id" : ObjectId("5d9482f3ff7ab743f0542070")
},
"_class" : "com.test.sample.model.City"
}
/* 3 */
{
"_id" : ObjectId("5d948333ff7ab743f054208b"),
"name" : "Akkaraipattu",
"district" : {
"$ref" : "district",
"$id" : ObjectId("5d9482f3ff7ab743f0542071")
},
"_class" : "com.test.sample.model.City"
}
this is the repository class for the above city document class
#Repository
public interface CityDao extends MongoRepository<City,String> {
List<City> findByDistrict(String id);
}
in the city class, i have used referenced document class called District. this a another document. I need to get the cities which belong to one district. findByDistrict(String id) method doesn't return values. Its just returning empty List. So How can i do this ?
I have tried with another alternative.As #pvpkirn said, You cannot query with #DBRef. But i tried with MongoOperations. With this we can pass the Filter objects as Json object. Using this i got the answer. This is what i tried.
public List<City> findByDistrictId(String districtId) {
final Bson filter = eq("district.$id", new ObjectId(districtId));
FindIterable<Document> documents = super.mongoOperations.getCollection("city").find(filter);
List<City> cities = new ArrayList<>();
for(Document document : documents){
City city = new City(document.getObjectId("_id").toString(),document.getString("name"),new District(districtId));
cities.add(city);
}
return cities;
}
in here i have used com.mongodb.client.model.Filters.eq to get the relevant bson object.
How to fetch the document by array of value from MONGODB using SPRING DATA.?
My document
{
"id": "5b18fdef89d67e272025f2e3",
"date": "2018-05-10 11:31:37",
"active": true,
"obsolete": false,
"tenant": {
"id": "5ad847e54925fb0fa4424e1a"
},
"plan": {
"id": "5ad7115f7b4152204c86fce6"
},
"log": [
"5b18fdef89d67e272025f2e4"
],
"lineItem": [
"5b18fdef89d67e272025f2e5",
"5b18fdef89d67e2720259899",
"5b18fdef89d67e272025sd5s"
]
}
{
"id": "5b18fdef89d67e272025f232",
"date": "2018-05-12 11:31:37",
"active": true,
"obsolete": false,
"tenant": {
"id": "5ad847e54925fb0fa4424e1a"
},
"plan": {
"id": "5ad7115f7b4152204c86fce6"
},
"log": [
"5b18fdef89d67e272025f23434"
],
"lineItem": [
"5b18fdef89d67e272025f111",
"5b18fdef89d67e2720259222",
"5b18fdef89d67e272025s333"
]
}
I want filter the document by lineItem array. If I give the lineItem value "5b18fdef89d67e2720259222" it will be return document which holds the same lineitem.
Model class
#Document(collection = "trn_inventory")
public class Inventory {
#Id
private String id;
private String date;
private List<String> lineitem;
private String tenant, plan;
private List<String> log;
private boolean active, obsolete;
//getters and setters
}
Repository
#Repository
public interface InventoryRep extends MongoRepository<Inventory, String> {
public List<Inventory> findByLineitemIn(String lineitem);
}
I have done the mistake in Repository. After spend the long time, I found it myself (stupid coder). The problem is parameter of the findByLineitemIn method is String that should be List type.
Here is the corrected Repository...
#Repository
public interface InventoryRep extends MongoRepository<Inventory, String> {
public List<Inventory> findByLineitemIn(List<String> lineitem);
}
How foolish is this.. Isn't it? I think this will helpful for some other coder like me. ;)
First thanks in advance for the help.
I have an application with Spring Boot and mongo using Spring Data and I have something like this:
#Document("products")
class Product {
#Id
private String $id;
private String $name;
private Money price;
private Money deliveryPrice;
}
class Money {
private BigDecimal amount;
private Currency currency;
}
If I save a product it saves like:
{
_id: ObjectId("AAAA"),
name: "Product 1",
price: {
amount: "100",
currency: "EUR"
},
deliveryPrice: {
amount: "10",
currency: "EUR"
}
}
It's correct but I don't like how it saves.
I would like to store like:
{
_id: ObjectId("AAAA"),
name: "Product 1",
price: DecimalNumber(100),
deliveryPrice: DecimalNumber(10),
currency: "EUR"
}
That way I am not duplicating information that is not needed in all the prices value.
How can I solve this?
Is this the best solution? In case not how should it be?
Thanks
class Money {
private BigDecimal amount;
#Transient
private Currency currency;
}
Now the currency property will not be persisted in MongoDB.
I'd like to iterate the following mongo db collection in java8
{ "_id" : ObjectId("59d1dc99a1a79605342f15a7"), "_class" : "com.test.User", "vehicle" : [ { "name" : "aaa", "color" : "blue" } ], "count" : 1,"createdBy" : "Admin", "lastModifiedBy" : "Admin" }
Expected O/P fields:
_id,name,color,count,createdBy
I tried the below
queryvalue.stream().flatMap(vehicle->vehicle.getVehicles().stream()).collect(Collectors.toList());
queryvalue is the one where i'm pulling the data from spring mongo db repository. I'm new to java8 pls help.
Below are the classes:
Class User{
#CreatedDate
protected DateTime createdDate;
#LastModifiedDate
protected DateTime lastModifiedDate;
List<Vehicle> vehicle;
public void setCreatedDate(DateTime createdDate) {
this.createdDate = createdDate;
}
public String getCreatedDate() {
return createdDate;
}
public List<Vehicle> getVehicles() {
return vehicle;
}
public void setVehicle(List<Vehicle> vehicle) {
this.vehicle= vehicle;
}
-- similarly for lastModifieddate and comments etc--
}
Class Vehicle{
private String name;
private string color;
public void setColor(String color){
this.color = color;
return this;
}
public String getColor(){
return color;
}
public void setName(String name){
this.name = name;
return this;
}
public void getName(){
return name;
}
}
And am pulling using this:
List<Vehicle>queryvalue = repository.findByVehicleName(vehiclename);