Spring Boot MongoDB - MongoDB cannot generate 'ID' - spring

I have some problem with my Spring Boot application.
When I save one document in my repository application works fine, but when I save more than one documents, my aplication not working. Here is my code.
Article.java
import org.springframework.data.annotation.Id;
public class Article {
#Id
private String id;
private String title;
private String description;
public Article() {}
public Article(String title, String description) {
this.title = title;
this.description = description;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Override
public String toString() {
return "Article{" +
"id='" + id + '\'' +
", title='" + title + '\'' +
", description='" + description + '\'' +
'}';
}
}
ArticleRepository.java
public interface ArticleRepository extends MongoRepository<Article, String> {}
DatabaseLoader.java
import java.util.HashSet;
import java.util.Set;
#Component
public class DatabaseLoader implements CommandLineRunner {
#Autowired
private ArticleRepository articleRepository;
#Override
public void run(String... args) throws Exception {
articleRepository.deleteAll();
// example 1: if I save one document to my repo everything works fine
// example: articleRepository.save(new Article("Title 1", "description 1"));
// console returns: Article{id='596f480e4e118123574a13f1', title='Title 1', description='description 1'}
// but here is problem
Set<Article> articleList = new HashSet<Article>(){
{
add(new Article("Title 1", "description 1"));
add(new Article("Title 2", "description 2"));
}
};
// because if I try to save my collection
articleRepository.save(articleList);
// console returns: com.mongodb.DuplicateKeyException:
// Write failed with error code 11000 and error message
// 'insertDocument :: caused by :: 11000 E11000 duplicate key
// error index: test.article.$user dup key: { : null }'
System.out.println(articleRepository.findAll());
}
}
Application.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(SimpleMongoApplication.class, args);
}
}
Do you know, why I have this problem?
Thank you for all your answers.

OK, here is #Afridi's solution.
All you need to do is adding #Document(collection="collection-name") annotation in your document. here is an example:
#Document(collection = "articles") // here is solution
public class Article {
#Id
private String id;
private String title;
private String description;
//getters, setters and constructor
}

Related

How i can separate a table which have null and non null elements using spring concept

for instance, I have a table with different locations and their description too. Now I need to print the locations which have descriptions on one page or in one box and simultaneously the locations which do not have descriptions should be displayed on another page.
NOTE:
this has to be done by using spring concept only
for reference, I was able to print the locations which have no descriptions in the below fashion.
entity
package com.test.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
#Entity
#Table(name= "loc_dtls")
public class Location {
#Id
#GeneratedValue(strategy = jakarta.persistence.GenerationType.IDENTITY)
private long id;
#Column(name="place_name")
private String placeName;
#Column(name="place_description")
private String placeDesc;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getPlaceName() {
return placeName;
}
public void setPlaceName(String placeName) {
this.placeName = placeName;
}
public String getPlaceDesc() {
return placeDesc;
}
public void setPlaceDesc(String placeDesc) {
this.placeDesc = placeDesc;
}
#Override
public String toString() {
return "Location [id=" + id + ", placeName=" + placeName + ", placeDesc=" + placeDesc + "]";
}
}
controller
#GetMapping("/")
public String singleElement(Model m) {
List<Location> util = locRepo.findByplaceDesc(null);
m.addAttribute("unlist_places", util);
return "index";
}
repository
#Repository
public interface LocationRepository extends JpaRepository<Location, Long> {
public List<Location> findByplaceName(String placeName);
public List<Location> findByplaceDesc(String placeDesc);
}
html
<select>
<option>--select--</option>
<option th:each="p : ${unlist_places}"
th:text="${p.placeName}">
</option>
</select>
MySql Database

How to send a Request body in postman for Embedded entity class in spring data jpa?

Can anyone please help me on how to send a nested json requestbody in postman for the below entity class.
ProcessRequestInfo.java
import java.sql.Date;
import java.time.ZonedDateTime;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="PROCESS_REQUEST_INFO")
public class ProcessRequestInfo {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private int id;
private String userName;
private String contactNumber;
#Embedded
private DefectiveComponentInfo defectiveComponentInfo;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getContactNumber() {
return contactNumber;
}
public void setContactNumber(String contactNumber) {
this.contactNumber = contactNumber;
}
public DefectiveComponentInfo getDefectiveComponentInfo() {
return defectiveComponentInfo;
}
public void setDefectiveComponentInfo(DefectiveComponentInfo defectiveComponentInfo) {
this.defectiveComponentInfo = defectiveComponentInfo;
}
#Override
public String toString() {
return "ProcessRequestInfo [id=" + id + ", userName=" + userName + ", contactNumber=" + contactNumber
+ ", defectiveComponentInfo=" + defectiveComponentInfo + "]";
}
public ProcessRequestInfo(int id, String userName, String contactNumber,
DefectiveComponentInfo defectiveComponentInfo, ZonedDateTime date) {
super();
this.id = id;
this.userName = userName;
this.contactNumber = contactNumber;
this.defectiveComponentInfo = defectiveComponentInfo;
}
public ProcessRequestInfo() {
super();
// TODO Auto-generated constructor stub
}
}
DefectiveComponentInfo.java
import javax.persistence.Embeddable;
#Embeddable
public class DefectiveComponentInfo {
private String componentType;
private String componentName;
private Long quantity;
private String description;
public String getComponentType() {
return componentType;
}
public void setComponentType(String componentType) {
this.componentType = componentType;
}
public String getComponentName() {
return componentName;
}
public void setComponentName(String componentName) {
this.componentName = componentName;
}
public Long getQuantity() {
return quantity;
}
public void setQuantity(Long quantity) {
this.quantity = quantity;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Override
public String toString() {
return "DefectiveComponentDetail [componentType=" + componentType + ", componentName=" + componentName
+ ", quantity=" + quantity + ", description=" + description + "]";
}
public DefectiveComponentInfo(String componentType, String componentName, Long quantity, String description) {
super();
this.componentType = componentType;
this.componentName = componentName;
this.quantity = quantity;
this.description = description;
}
public DefectiveComponentInfo() {
super();
// TODO Auto-generated constructor stub
}
}
I have tried few nested json requestbody in postman but the inner class data is getting null.
Below is my json request body which I have tried.
{
"userName" : "sam",
"contactNumber" : "96014587555",
"DefectiveComponentInfo":
[ {
"componentType":"Integral",
"componentName":"Bummper",
"quantity":5,
"description": "Repair product"
}]
}
Thanks in advance!!!
You are almost there. few things to be corrected
{
"userName" : "sam",
"contactNumber" : "96014587555",
"defectiveComponentInfo": {
"componentType":"Integral",
"componentName":"Bummper",
"quantity":5,
"description": "Repair product"
}
}
What i have corrected here
As per #Ausgefuchster already mentioned about the incorrect usage of [] array syntax. Removed it.
Your property name is defectiveComponentInfo not capital D.
Try this:
"DefectiveComponentInfo":
{
"componentType": "Integral",
"componentName": "Bummper",
"quantity": 5,
"description": "Repair product"
}
Because you're using [] but these indicate a list.

Spring Data Elasticsearch Inheritance

Is there any way to make a super-class document (e.g. index name = user) and create two child classes (Admin, Guest) to save all this to user index but with different fields? E.g. Add to super-class field type and based on this field fetch right entity? ELK 7.19, Spring Data 4.3.1.
You can do that. Make the base class abstract. I have this in a test setup with the following classes:
#Document(indexName = "type-hints")
public abstract class BaseClass {
#Id
private String id;
#Field(type = FieldType.Text)
private String baseText;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getBaseText() {
return baseText;
}
public void setBaseText(String baseText) {
this.baseText = baseText;
}
#Override
public String toString() {
return "BaseClass{" +
"id='" + id + '\'' +
", baseText='" + baseText + '\'' +
'}';
}
}
public class DerivedOne extends BaseClass {
#Field(type = FieldType.Text)
private String derivedOne;
public String getDerivedOne() {
return derivedOne;
}
public void setDerivedOne(String derivedOne) {
this.derivedOne = derivedOne;
}
#Override
public String toString() {
return "DerivedOne{" +
"derivedOne='" + derivedOne + '\'' +
"} " + super.toString();
}
}
public class DerivedTwo extends BaseClass {
#Field(type = FieldType.Text)
private String derivedTwo;
public String getDerivedTwo() {
return derivedTwo;
}
public void setDerivedTwo(String derivedTwo) {
this.derivedTwo = derivedTwo;
}
#Override
public String toString() {
return "DerivedTwo{" +
"derivedTwo='" + derivedTwo + '\'' +
"} " + super.toString();
}
}
interface TypeHintRepository extends ElasticsearchRepository<BaseClass, String> {
SearchHits<? extends BaseClass> searchAllBy();
}
#RestController
#RequestMapping("/typehints")
public class TypeHintController {
private static final Logger LOGGER = LoggerFactory.getLogger(TypeHintController.class);
private final TypeHintRepository repository;
public TypeHintController(TypeHintRepository repository) {
this.repository = repository;
}
#GetMapping
public void test() {
List<BaseClass> docs = new ArrayList<>();
DerivedOne docOne = new DerivedOne();
docOne.setId("one");
docOne.setBaseText("baseOne");
docOne.setDerivedOne("derivedOne");
docs.add(docOne);
DerivedTwo docTwo = new DerivedTwo();
docTwo.setId("two");
docTwo.setBaseText("baseTwo");
docTwo.setDerivedTwo("derivedTwo");
docs.add(docTwo);
repository.saveAll(docs);
SearchHits<? extends BaseClass> searchHits = repository.searchAllBy();
for (SearchHit<? extends BaseClass> searchHit : searchHits) {
LOGGER.info(searchHit.toString());
}
}
}

Adding default values for collection of objects inside outer object

I am trying to add default values to property attributes.I have one class inside which i have other class type injected as list.
I am able to get the default values for all attributes even on dependent class.I want to know is there any way using #value to add one more list of default values of custom objects.
My model classes are-
package com.example.test.Model;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class Employee {
#Value("1")
private Integer id;
#Value("Anubham")
private String name;
#Autowired
private List<Departments>departments;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Departments> getDepartments() {
return departments;
}
public void setDepartments(List<Departments> departments) {
this.departments = departments;
}
public Employee() {
super();
}
public Employee(Integer id, String name, List<Departments> departments) {
super();
this.id = id;
this.name = name;
this.departments = departments;
}
#Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", departments=" + departments + "]";
}
}
Another one is:
package com.example.test.Model;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class Departments {
#Value("1")
private int id;
#Value("computer")
String subject;
public Departments() {
super();
}
public Departments(int id, String subject) {
super();
this.id = id;
this.subject = subject;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
#Override
public String toString() {
return "Departments [id=" + id + ", subject=" + subject + "]";
}
}
I am getting output as Employee [id=1, name=Anubham, departments=[Departments [id=1, subject=computer]]].
I want to have one more record for departments field.
I wonder is it possible using #value without using any other way.
In your example "Departments" is a bean that is injected into Employee bean. If you want to have multiple departments, you have to create interface/abstraction "Department" and implement it in beans with concrete values that you want (DepartmentA, DepartmentB).
But Value annotation is not meant do inject static content but rather values from properties files. I don't know what you want to achieve this way.

DuplicateKeyException in mongodb and spring boot

I am using Spring Boot and MongoDB and I am able to store a document in MongoDB successfully. When I was trying to insert a second document, it is showing duplicatekeyexception. The total message of exception is as follows:
com.mongodb.DuplicateKeyException: Write failed with error code 11000
and error message 'E11000 duplicate key error collection:
Football_Admin.SignUp index: id dup key: { : 0 }'
The code is as follows:
SignUpRepository.java
package com.admin.Repository;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import com.admin.Model.SignUp;
#Repository
public interface SignUpRepository extends MongoRepository<SignUp,String>{
}
Controller
#Controller
#RequestMapping("/SignIn_Up")
public class HomeController {
#Autowired
SignUpRepository repository;
#RequestMapping(value = "/addadmin", method = RequestMethod.POST)
public String addAdmin(#ModelAttribute("SignUp") SignUp sign) throws NoSuchAlgorithmException,InvalidKeySpecException {
String originalPassword = sign.getPassword();
String generatedSecuredPasswordHash = generateStorngPasswordHash(originalPassword);
String email = sign.getEmail();
String fullname = sign.getFullName();
try {
sign.setEmail(email);
sign.setFullName(fullname);
sign.setPassword(generatedSecuredPasswordHash);
repository.save(sign);
}
catch (DuplicateKeyException e) {
e.printStackTrace();
}
System.out.println(generatedSecuredPasswordHash);
System.out.println("Email name is:"+sign.getEmail());
System.out.println("Full Name is:"+sign.getFullName());
System.out.println("Password is:"+sign.getPassword());
return "welcome";
}
Entity
package com.admin.Model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
#Document(collection="SignUp")
public class SignUp {
#Id
private int id;
private String fullName;
private String email;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String toString() {
return id+""+fullName+""+password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
MongoDb driver don't know how to create a unique Id of type int when inserting so you received unique index exception
So either you manually create and maintain your index (quite hard) or change your id field type to ObjectId

Resources