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
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);
}
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
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
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);
}
}
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;
}