DuplicateKeyException: error code 11000 and error message 'E11000' - java

i want to update/replace document using id field only, i am using mongoTemplate.save(p, collection) method but i am getting DuplicateKeyException: error code 11000 and error message 'E11000'
public class MongoDAO {
#Autowired
#Qualifier("mongoTemplate")
private MongoTemplate mongoTemplate;
private static final String PERSON_COLLECTION = "person";
public MongoTemplate getMongoTemplate() {
return mongoTemplate;
}
public void update(Object p) {
this.mongoTemplate.save(p, PERSON_COLLECTION);
}
}
This is my person DAO
public class PersonDAO{
#Autowired
MongoDAO mongoDAO;
public void updatePerson(){
//read
Person p1 = mongoDAO.readById("1234");
//update
p1.setName("David");
mongoDAO.update(p1);
}
}
Person.java class
package com.mongo.andy;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Field;
public class Person {
#Id
private String id;
#Field
private String 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;
}
}
I simply want to get the object from mongodb change the values and update the document based on _id
Using mongooperation.save() or mongotemplate.save() i am getting below error
com.mongodb.DuplicateKeyException: Write failed with error code 11000 and error message 'E11000 duplicate key error collection: Person.person index: _id_ dup key: { : "5996f1d43b6af5c797a1cf4g" }'
at com.mongodb.operation.BaseWriteOperation.convertBulkWriteException(BaseWriteOperation.java:236)
at com.mongodb.operation.BaseWriteOperation.access$300(BaseWriteOperation.java:60)
at com.mongodb.operation.BaseWriteOperation$1.call(BaseWriteOperation.java:146)
at com.mongodb.operation.BaseWriteOperation$1.call(BaseWriteOperation.java:133)
at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.java:230)
at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:221)
at com.mongodb.operation.BaseWriteOperation.execute(BaseWriteOperation.java:133)
at com.mongodb.operation.BaseWriteOperation.execute(BaseWriteOperation.java:60)
at com.mongodb.Mongo.execute(Mongo.java:781)
at com.mongodb.Mongo$2.execute(Mongo.java:764)
at com.mongodb.DBCollection.executeWriteOperation(DBCollection.java:333)
at com.mongodb.DBCollection.insert(DBCollection.java:328)
at com.mongodb.DBCollection.insert(DBCollection.java:319)
at com.mongodb.DBCollection.insert(DBCollection.java:289)
at com.mongodb.DBCollection.insert(DBCollection.java:255)
at com.mongodb.DBCollection.insert(DBCollection.java:192)
at org.springframework.data.mongodb.core.MongoTemplate$9.doInCollection(MongoTemplate.java:1051)
at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:479)
at org.springframework.data.mongodb.core.MongoTemplate.insertDBObject(MongoTemplate.java:1046)
at org.springframework.data.mongodb.core.MongoTemplate.doInsert(MongoTemplate.java:855)
at org.springframework.data.mongodb.core.MongoTemplate.doSaveVersioned(MongoTemplate.java:1001)
at org.springframework.data.mongodb.core.MongoTemplate.save(MongoTemplate.java:985)
at com.mcmcg.dia.account.metadata.dao.MongoDAO.update(MongoDAO.java:105)
at com.mcmcg.dia.account.metadata.service.AccountOALDService.mongotestapi(AccountOALDService.java:265)
at com.mcmcg.dia.account.metadata.service.AccountOALDService$$FastClassBySpringCGLIB$$7f85f843.invoke(<generated>)
Please provide the solution and suggest if there is any other way to update/replace documents in mongodb using spring-data on the basis of id field only. I have large custom object and not interesting writing any queries for update.
I was able to do so in couchbase db using upsert(), finding similar way in mongodb.

Instead of this.mongoTemplate.save(p, PERSON_COLLECTION); try with:
public void update(Object p) {
BasicDBObject dbObject = new BasicDBObject();
mongoTemplate.getConverter().write(p, dbObject);
mongoTemplate.upsert(new Query(Criteria.where("_id").is(((Person) p).getId())),
Update.fromDBObject(dbObject, "_id"), PERSON_COLLECTION);
}
The solution is similar to how the upsert method it is implemented in MongoTemplate.

Related

Spring boot CrudRepository saves bad data

i have problem with saving data in DB.I'm new in Spring Boot. When i run my program the result of writen data is: packagename#randomcode example:com.abc.patient.Patient#6e3e681e
This is my Entity class - Patient.java
#Entity
public class Patient {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
// getter, setter, constructor, etc
}
This is my CrudRepo PatientRepository.java
public interface PatientRepository extends CrudRepository<Patient,Integer> {
}
This is my Service class PatientService.java
#Service
public class PatientService {
#Autowired
private PatientRepository patientRepository;
public void savePatient (String name) {
Patient patient = new Patient(name);
patientRepository.save(patient);
}
public Optional<Patient> showPatient(int id) {
return patientRepository.findById(id);
}
public List<Patient> showAllPatients() {
List<Patient> patients = new ArrayList<>();
patientRepository.findAll().forEach(patients::add);
return patients;
}
}
I think that problem in in the savePatient method in this line:
Patient patients = new Patient(name);
I checked the "name" parameter and it's in 100% correct String. I'm using Derby DB.
The only problem you have is how you are printing out your Patient class. Define a proper toString() or just debug yourself to see the resulting fields. There is no problem in your JPA implementation.
See this question for the details of default toString
Try:
public void savePatient(Patient patient) {
patientRepository.save(patient);
}

Springboot could not extract ResultSet

Currently I am getting a problem with fetching mysql data for my springboot project:
There was an unexpected error (type=Internal Server Error, status=500).
could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
TestEntity.java
#Entity
public class TestEntity implements Serializable {
#Id
private int id;
private String p1;
private String p2;
private String p3;
public TestEntity() {
}
public TestEntity(int id, String p1, String p2, String p3){
this.id = id;
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getP1() {
return p1;
}
public void setP1(String p1) {
this.p1 = p1;
}
public String getP2() {
return p2;
}
public void setP2(String p2) {
this.p2 = p2;
}
public String getP3() {
return p3;
}
public void setP3(String p3) {
this.p3 = p3;
}
}
TestService.java
#Service
public class TestService {
#Autowired
private TestRepository testRepository;
public ArrayList<TestEntity> getAllTestEntities(){
ArrayList<TestEntity> list = new ArrayList();
testRepository.findAll().forEach(list::add);
return list;
}
public Optional getTestEntity(int id){
return testRepository.findById(id);
}
public void addTestEntity(TestEntity t){
testRepository.save(t);
}
public void removeTestEntity(int index){
testRepository.deleteById(index);
}
}
TestRepository.java
#Repository("mysql")
public interface TestRepository extends CrudRepository<TestEntity,Integer> {
}
TestController.java
#RestController
public class TestController {
#Autowired
private TestService testService;
#RequestMapping("/test/AllUnits")
public ArrayList<TestEntity> getAllTestUnits(){
return testService.getAllTestEntities();
}
#RequestMapping("/test/{id}")
public Optional getAllTestUnit(#PathVariable int id){
return testService.getTestEntity(id);
}
#RequestMapping(method=RequestMethod.POST,value = "/test" )
public void addTestUnit(#RequestBody TestEntity t){
testService.addTestEntity(t);
}
#RequestMapping(method=RequestMethod.DELETE,value = "/test/{id}" )
public void deleteTestUnit(#RequestBody Integer id){
testService.removeTestEntity(id);
}
#RequestMapping("/test/welcome")
public String welcome(){
return "welcome to springboot";
}
}
Edit: application.properties
cloud.aws.region.auto=true
cloud.aws.region.static=us-east-2
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://alyxdev.czcdgqfkwsnr.us-east-2.rds.amazonaws.com:3306/CryptoCurrency
spring.datasource.username=*******
spring.datasource.password=*******
I am able to get the /test/welcome mapping working so I believe my implementation of the service and controller is correct. So I am wondering if I made a mistake for accessing my database in my repository or should I use a JpaRepository instead of a CrudRepository and use an explicit query?
Edit Stack Trace:
org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'CryptoCurrency.test_entity' doesn't exist
In you Entity class i.e. TestEntity.java, you need to specify which table that your referring to
#Entity
#Table(name="tbl_something")
public class TestEntity implements Serializable {
And use of CrudRepository would be fine for excessing the database.
The application.properties file looks good to me.
I found the solution to the problem I was having apparently by renaming the table to all lowercase characters (test_table) in SQL and then using that table instead of Test_table Springboot was able to find that table and link map it to my entity class. I have no idea why it works this way. Maybe something to do with the Netbeans IDE I am using perhaps?
If annotate your entity class with #Table(name = "EmplyeeSalary") then JPA generates employee_salary as the table name. According to the naming convention at every uppercase found in the name, a new word will be generated with all lower case and will be separated from previous using _.
If you annotate your entity class like #Table(name = "AbcDefGhi") then JPA will look for abc_def_ghi table.
In my case it was due to a column was not added in table But in my entity class I am expecting that

Hibernate Criteria Projection of non scalar values

Is there any way to project multiple values for an root entity object using Criteria?
Assume we have these classes (With the proper mappings):
class Boss {
private String name;
private List<Employee> employees;
// setters and getters and more stuff
}
class Employee {
private String name;
// setters and getters and more stuff
}
Then i am trying to do this :
public void test() {
Criteria criteria = this.getSession().createCriteria(Boss.class);
criteria.createAlias("employees","employees");
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.property("name"), "name");
projectionList.add(Projections.property("employees.name"), "subordinatesNames");
criteria.setProjection(projectionList);
criteria.setResultTransformer(new AliasToBeanResultTransformer(BossBean.class));
List<BossBean> results = criteria.list(); // fails here
for (BossBean bossBean : results) {
System.out.println (bossBean);
}
}
This is how the Bean looks like (nothign special, just for grouping values) :
public static class BossBean {
private String name;
private List<Strings> subordinatesNames;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Strings> getSubordinatesNames() {
return subordinatesNames;
}
public void setSubordinatesNames(List<Strings> subordinatesNames) {
this.subordinatesNames = subordinatesNames;
}
}
The exception is this :
2014-06-06 13:37:38 [main] ERROR org.hibernate.property.BasicPropertyAccessor - expected type: java.util.List, actual value: java.lang.String.
I Guess is trying to fit the String returned from Boss(root object) -> (A)Employee(association) ->name(value) into a List.
I want to auto magically get all inserted in the List. Is there a way to achieve this using Criteria? If not, how i can achieve it?
Thanks in advance!
Grettings
VĂ­ctor

Spring Data : Java configuration for MongoDB without XML

I tried the Spring Guide Accessing Data with MongoDB. What I can't figure out is how do I configure my code to not use the default server address and not use the default database. I have seen many ways to do it with XML but I am trying to stay with fully XML-less configurations.
Does anyone have an example that sets the server and database without XML and can be easily integrated into the sample they show in the Spring Guide?
Note: I did find how to set the collection (search for the phrase "Which collection will my documents be saved into " on this page.
Thank you!
p.s. same story with the Spring Guide for JPA -- how do you configure the db properties -- but that is another post :)
It would be something like this for a basic configuration :
#Configuration
#EnableMongoRepositories
public class MongoConfiguration extends AbstractMongoConfiguration {
#Override
protected String getDatabaseName() {
return "dataBaseName";
}
#Override
public Mongo mongo() throws Exception {
return new MongoClient("127.0.0.1", 27017);
}
#Override
protected String getMappingBasePackage() {
return "foo.bar.domain";
}
}
Example for a document :
#Document
public class Person {
#Id
private String id;
private String name;
public Person(String name) {
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;
}
}
Example for a repository :
#Repository
public class PersonRepository {
#Autowired
MongoTemplate mongoTemplate;
public long countAllPersons() {
return mongoTemplate.count(null, Person.class);
}
}

Cannot render my returned Backbone models

My first post so please go easy on me..
I am currently writing a hospital rostering web application in BackboneJS + JAX-RS. It has been ok until now but I can't for the life of me work this one out...
In my Group model I have a Users collection.
This is returned as a List<User> from JAX and User has the #XmlRootElement annotation on it.
But when I call fetch it fills the Group model with an array of User models instead of a Users collection.
Is there a way to tell JAX to return my list of User models as a Users collection?
Any help appreciated!
EDIT:
Group model in Backbone:
window.Group = Backbone.Model.extend({
urlRoot: "api/groups",
defaults: {
name: ''
},
validate: function(attrs){
var errors = [];
if (!attrs.name) {
errors.push({name: 'name', message: 'Please fill in the name field.'});
}
if(!attrs.users || attrs.users.length == 0){
errors.push({name: 'users', message: 'Please add at least 1 user.'});
}
return errors.length > 0 ? errors : false;
}
});
Group model in Java:
package org.jakeduncandev.roster;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Group {
private int id;
private String name;
private int ownerid;
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getOwnerid() {
return ownerid;
}
public void setOwnerid(int ownerid) {
this.ownerid = ownerid;
}
}
JSON returned:
"groups":[{"name":"mates","id":71,"users":[{"id":6,"password":"<PASSWORD>","email":"<EMAIL>","firstName":"Jake","lastName":"Duncan"},{"id":7,"password":"<PASSWORD>","email":"<EMAIL>","firstName":"alec","lastName":"stearn"}],"ownerid":0}]
SOLVED!
I added a parse method to my Group model. And then when I was instantiating my collection I used the option: {parse: true} and then it calls the parse method for each model.
Thanks for your help everyone and to user10 for suggesting overriding the parse method!
parse: function(response){
response.users = new window.Users(response.users);
return response;
}

Categories

Resources