Custom method for update query with spring data MongoRepository - java

I am using org.springframework.data.mongodb.repository.MongoRepository. I have written some custom method like below,
public interface DocRepository extends MongoRepository<Doc, String> {
Doc findByDocIdAndAssignmentId(final String docId, final String assignemtId);
}
How can I write a custom method which update all entries when meeting a criteria.
For example set document tilte field to "abc" if assignment id is "xyz"?

1) You need to create inteface e.g CustomDocRepository and add this interfaces as Base for your DocRepository:
public interface DocRepository extends MongoRepository<Doc, String>, CustomDocRepository {
void updateDocumentTitle(String id, String title);
}
2) You need to add implementation for the DocRepository:
#Repository
public class CustomDocRepositoryImpl implements DocRepository {
#Autowired
private MongoTemplate mongoTemplate;
#Override
public void updateDocumentTitle(String id, String title) {
Query query = new Query().addCriteria(where("_id").is(id));
Update update = new Update();
update.set("title", title);
mongoTemplate.update(Doc.class).matching(query).apply(update).first();
}
}
That is all you need to do

Provided you have an autowired attribute mongoTemplate in your service class. Add the below code to update the document.
Query query = new Query();
query.addCriteria(Criteria.where("assignmentId").is("xyz"))
Update update = new Update();
update.set("title", "abc");
mongoTemplate.updateFirst(query, update, Doc.class);
You dont need to have findByDocIdAndAssignmentId for the update purpose.

I found com.mongodb.MongoClient to achieve the above

Related

How can we implement custom find methods in CrudRepository to get only specific columns from a database?

I have to execute a SQL query in my repository:
public interface UserRequestResponseRepository extends JpaRepository<UserRequestResponse, Integer> {
//public static final String FIND_QUERY = "select user.u_httpstatus ,user.u_queryparam from UserRequestResponse user";
public static final String FIND_QUERY =
"select new com.abc.datacollection.entity.UserRequestResponse(user.u_httpstatus ,user.u_queryparam) from UserRequestResponse user";
#Query(value = FIND_QUERY)
public List<UserProjection> getAllRequestResponseRecords();
}
where UserProjection is a projection that I defined:
public interface UserProjection {
String getU_httpstatus();
String getU_queryparam();
}
The class userRequestResponse has more fields than u_httpstatus and u_queryparam, but I want only these 2 fields in my response.
public #ResponseBody List<UserRequestResponse> getAllRequestResponseRecords() {
return userRequestResponseRepository.findAll() ;
}
how do I modify the above code (findAll()) to get results from my custom query and not the results from the default CrudRepository findAll() (which returns all the fields).
First you don't need to add a #Query to make projections work. Just having the UserProjection as the return type of the method in repository should be enough. More about this here
Secondly, you can just have the following method in your repository as a projection-based findAll method;
public List<UserProjection> findAllProjectedBy();

Spring data JPA #Query mapping with named columns

I use Spring Boot 1.5 and spring data JPA with MySQL. I tried to run a simple counting query on a single table, but could not find a better way to map the Query results than this.:
Repository:
public interface VehicleRepository extends JpaRepository<Vehicle, String> {
#Query("select v.sourceModule as sourceModule, count(v) as vehicleCount from Vehicle v group by v.sourceModule")
List<Object[]> sourceModuleStats();
}
Service:
#Override
public List<SourceModuleStatDTO> getSourceModuleStats() {
List<Object[]> objects = vehicleRepository.sourceModuleStats();
return objects.stream()
.map(o->SourceModuleStatDTO.from((String)o[0], (Long)o[1]))
.collect(Collectors.toList());
}
I use org.immutables, so the DTO.:
#Value.Immutable
#JsonSerialize(as = ImmutableSourceModuleStatDTO.class)
#JsonDeserialize(as = ImmutableSourceModuleStatDTO.class)
public abstract class SourceModuleStatDTO {
public abstract String sourceModule();
public abstract long vehicleCount();
public static SourceModuleStatDTO from(String sm, long c) {
return ImmutableSourceModuleStatDTO.builder()
.sourceModule(sm)
.vehicleCount(c)
.build();
}
}
The problem here is the mapping, I need to cast the results or manually check everything. Even JdbcTemplate has better mapping capabilities, I can't believe there is no better way to do this.
I tried this too: https://stackoverflow.com/a/36329166/840315 , but you need to hard code classpaths into the Query to get it work and also I would still need to map the objects to Immutables.
Using JdbcTemplate, you can use the RowMapper (src) :
private static final class EmployeeMapper implements RowMapper<Employee> {
#Override
public Employee mapRow(ResultSet rs, int rowNum) throws SQLException {
Employee employee = new Employee();
employee.setCountry(rs.getString("country"));
employee.setEmployeeName(rs.getString("employee"));
return employee;
}
}
Is there something similar for spring data JPA #Query?
How about using Projections as below?
static interface VehicleStats {
public String getSourceModule();
public Long getVehicleCount();
}
And your repository method would be
#Query("select v.sourceModule as sourceModule, count(v) as vehicleCount from Vehicle v group by v.sourceModule")
List<VehicleStats> sourceModuleStats();
In your Service class, you can use the interface methods as below.
List<VehicleStats> objects = vehicleRepository.sourceModuleStats();
return objects.stream()
.map(o->SourceModuleStatDTO.from(getSourceModule(),getVehicleCount() )
.collect(Collectors.toList());

How to update postgres table with Spring Boot JPARepository?

I have a Spring boot application thats committing object to Postgres DB using JPARepository. The code for my repository is as below:
public interface TestObjectDao extends JPARepository<TestObject, Long> {
List<TestObject> findByTestRefIdAndTestType(String testRefId,
Short testType);
TestObject save(TestObject testObject);
}
When I want to create, In my service implementation (implementing above interface) I used "save" method. But, when I try to update, it neither creates entry nor update it.
How can I update records in Postgres database? Below is my code snippet using for update:
#Component
public class TestObjectServiceImpl implements TestObjectService {
#Inject
private TestObjectDao TestObjectDao;
#Override
public TestObjectResponse createTestObject(String testRefId, String testType, TestObject testObject) throws Exception{
--
--
--
try {
//update object
testObject = TestObjectDao.save(testObject);
}
}
catch (Exception ex) {
throw new Exception("Object could not be modified");
}
TestObjectResponse testObjectResponse = new TestObjectResponse();
testObjectResponse.setVal(testObject);
return testObjectResponse;
}
}
I have gone through all related posts but didn't get satisfactory resolution.
Spring detects wether it needs to save or create an entity by checking it's ID.
In your case, you need to select it first, so Spring will populate the entity properly:
try {
testObject = TestObjectDao.findOne(testRefId);
//update object
testObject = TestObjectDao.save(testObject);
}
Please refer section 2.2.1:
http://docs.spring.io/spring-data/jpa/docs/1.4.1.RELEASE/reference/html/jpa.repositories.html
Note that if only some columns are to be updated, it's much more efficient to use:
#Modifying
#Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);

Spring Boot extending CrudRepository

I'm using Hibernate in a Spring Boot app. I'm making a new CrudRepository for all my Model objects, to do basic CRUD tasks. They look like this:
#Repository
public interface FoobarCrudRepo extends CrudRepository<Foobar, Long> {
}
But then I always need to do some additional things, like custom search queries with inequalities and such. I follow a pattern like this:
#Repository
public class FoobarDao {
#PersistenceContext
EntityManager em;
public List<Foobar> findFoobarsByDate(Date date) {
String sql = "select fb from Foobar fb where createdDate > :date";
...
return query.getResultList();
}
}
My question is, can I combine these two concepts into a single class? I tried making it an abstract class, like so:
#Repository
public abstract class FoobarCrudRepo extends CrudRepository<Foobar, Long> {
#PersistenceContext
EntityManager em;
public List<Foobar> findFoobarsByDate(Date date) {
String sql = "select fb from Foobar fb where createdDate > :date";
...
return query.getResultList();
}
}
But then Spring didn't create a bean for it.
How can I accomplish this?
Thanks!
There are lots of ways you could probably accomplish this. If you really need absolute control try this
interface FoobarRepositoryCustom{
List<Foobar> findFoobarsByDate(Date date);
}
interface FoobarRepository extends CrudRepository<Foobar, Long>, FoobarRepositoryCustom
public class FoobarRespoitoryImpl implements FoobarRepositoryCustom{
#PersistenceContext private EntityManager em;
public List<Foobar> findFoobarsByDate(Date date) {
String sql = "select fb from Foobar fb where createdDate > :date";
...
return query.getResultList();
}
}
There is also the possibility to go a simpler route and the query can be auto generated for you based on the method name. In your example you could just add this to your FoobarCrudRepo and Spring should do the rest assuming Foobar has a property named CreatedDate
List<Foobar> findByCreatedDateGreaterThan(Date date);
For reference on how Spring can generate queries based on the method name see this http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation
Completely new to Spring Data, but having searched a bit it is my impression that you do not have to leave the interface to create custom logic - rather you would create either an annotated interface method, an interface method that follows a special naming scheme or a default interface method with custom logic:
Screenshot from Baeldung: Introduction to Spring.
Here is a link to the documentation. Notice "table 4. Supported keywords inside method names" which can be used to create interface methods, whose name conveys information to the code generator about which query to create (See part of table below).
The problem here is abstract keyword.
#Repository
public abstract class FoobarCrudRepo extends CrudRepository<Foobar, Long>
Spring will not create a bean for a class unless it is a concrete class.
That's why you are getting a bean for it.
This is what worked for me...
#SpringBootApplication(scanBasePackages = { "com.myproject" })
#EnableJpaRepositories(basePackages="com.myproject.sprinbootapp.repository")
#EntityScan("com.myproject.sprinbootapp.model")
public class SpringbootAppWithDatabaseApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootAppWithDatabaseApplication.class, args);
}
}
#Service
public class TopicService {
#Autowired
private TopicRepository topicRepository;
private List<Topics> topics = new ArrayList<Topics>();
public List<Topics> getAllTopics(){
List<Topics> listOfTopics = new ArrayList<Topics>();
topicRepository.findAll().forEach(listOfTopics::add);;
return listOfTopics;
}
}
#Entity
public class Topics {
#Id
private String id;
private String name;
public Topics(){
}
getters and setters...
}
public interface TopicRepository extends CrudRepository<Topics, String> {
}
we can use the JPA EntityManager for direct sql actions:
public interface VerificationsRepository extends
CrudRepository<Verification, Integer>,
DAOAccess
{ }
interface DAOAccess {
List findByEmail(String email);
}
class DAOAccessImpl implements DAOAccess {
#PersistenceContext private EntityManager em;
public List findByEmail(String email) {
String sql =
"select * from verifications where email = ?";
Query query = em.createNativeQuery(sql, Verification.class)
.setParameter(1, email);
return query.getResultList();
}
}

How to delete items in MongoRepository using query annotation?

I'm using Spring Data with MongoDB using MongoRepository.
I was wondering if it is possible do a delete by filter using query annotation. I have been looking here and google and I cannot find any documentation.
#Query(value="{'id' : $0}", delete = true)
public Person deleteById (String id);
Maybe you can use repository delete queries. Here is an example from documentation:
public interface PersonRepository extends MongoRepository<Person, String> {
List <Person> deleteByLastname(String lastname);
Long deletePersonByLastname(String lastname);
}
Using return type List will retrieve and return all matching documents before actually deleting them. A numeric return type directly removes the matching documents returning the total number of documents removed.
Try this, it's work for me.
#Repository
public interface DepartmentDao extends MongoRepository<Department, String> {
#DeleteQuery
void deleteByDepartment(String department);
}
OR
#Query(value="{'_id' : ?0}", delete = true)
public void deleteById(String id);
Unfortunately spring data doesn't provides any method to delete documents based on a query. And the #Query annotation is only for find documents.
What you could do is implement a custom repository that deletes documents based on what you want.
How to delete a list of ids in the query ?
#Query(value="{idList : $0}", delete = true)
Repository:
#Component
public interface SomeRepository extends MongoRepository<SomeObject, String> {
#Query("{ '_id' : ?0 }")
SomeObject findById(String _id);
}
Code in some class:
#Autowired
private SomeRepository pRepo;
public void delete(String id) {
pRepo.delete(pRepo.findById(id));
}
#Repository
public interface DepartmentDao extends MongoRepository<Department, String> {
void deleteByDepartment(String department);
}
is clean and shorter.

Categories

Resources