How to delete items in MongoRepository using query annotation? - java

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.

Related

How to add a comparator to querydsl Predicate?

I have the following webservice the automatically translates get parameter queries to database selects:
public interface PersonRepo extends
JpaRepository<Person, Long>,
QuerydslPredicateExecutor<Person> {
}
#GetMapping
public ResponseEntity getFiltered(
#QuerydslPredicate(root = Person.class) Predicate predicate, Pageable pageable) {
return ResponseEntity.ok(personRepo.findAll(predicate, pageable)));
)
}
The following queries could eg be executed:
GET /people?name=John&age=18
GET /people?name=John&age=18&page=1&sort=name,desc
Problem: I want to apply comparator queries as follows:
GET /people?name=John&age>18
GET /people?name=John&age>18&age<30
GET /people?name=John&age<30
Question: how could I achieve this? At least the later queries don't work.
I found a solution by defining a placeholder for the field, and using a QuerydslBinderCustomizer:
public interface PersonRepo extends
JpaRepository<Person, Long>,
QuerydslPredicateExecutor<Person>,
QuerydslBinderCustomizer<Person> {
default void customize(final QuerydslBindings bindings, final QPerson person) {
bindings.bind(cache.ageMin).first((path, value) -> person.age.goe(value));
bindings.bind(cache.ageMax).first((path, value) -> person.age.loe(value));
}
}
Of course the age fields then have to exist as transient fields, so that querydsl knows them:
#Entity
class Person {
#Transient
#QueryType(PropertyType.NUMERIC)
public int ageMin;
#Transient
#QueryType(PropertyType.NUMERIC)
private int ageMax;
}
You could use a single binding and use expressions from Query DSL value operators.
public interface PersonRepo extends
JpaRepository<Person, Long>,
QuerydslPredicateExecutor<Person>,
QuerydslBinderCustomizer<Person> {
default void customize(final QuerydslBindings bindings, final QPerson person) {
bindings.bind(cache.age).all((path, values) -> ExpressionProviderFactory.getPredicate(path, values));
}
}

Java spring JPA Repository Entity is not deleted

In my code, I fetch an entity and try to delete it, using the interface ProductRepository which extends JpaRepository:
#Repository
public interface ProductRepository extends JpaRepository<Product, Long> {}
Code, and System.out.println() output from code:
#PostMapping("/admin/product/delete")
public String deleteProduct(
#RequestParam String productId
){
Long id = Long.parseLong(productId);
System.out.println("long id from deleteProduct: " + id);
productService.deleteProductById(id);
return "redirect:/product";
}
sysout:
long id from deleteProduct: 38
Service method deleteProductById():
public void deleteProductById(long productId){
Product product = productRepository.getOne(productId);
System.out.println("Product:\n" + product);
productRepository.delete(product);}
sysout from deleteProductById:
Product: Product{id=38, productName='zip',
producer=lightmarket.mvc.model.domain.Producer#182a383}
But the entity is not deleted...
I must point out that all other CRUD operations work. Create, Update, Read - all are alright! Only 'delete' is not working.
JpaRepository extends CrudRepository, so you can use:
Crudrepository.deleteById() which in the case of your generic types, takes a long (See the documentation at ).
So, in your service, you would have something like:
#Service
public class ProductService {
#Autowired
ProductRepository repo;
public void deleteProductById(Long id) {
System.out.println("Deleting product with id: " + id);
// USE deleteById(Long id) and directly pass the id
// Defined in CrudRepository
repo.deleteById(id);
// DON'T use delete() and pass a product
//repo.delete(product);
}
}
Then your controller calls service.deleteProductById() from the service like normal
See documentation: https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html?is-external=true#deleteById-ID-
Maybe there is something wrong with your equals and hashcode of the Product class and the object you load from database is not the same you are trying to delete.
A better way for deleting a product by id would be using the id instead of the product object.
You could replace
productRepository.delete(product);
with
productRepository.delete(productId);
where productId is of type Long.
This would also avoid the additional query.

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 do I get distinct fields from MongoRepository/QueryDSL?

My Document is
#QueryEntity #Data #Document(collection = "MyCol") public class MyCol {
#Id private String _id;
private String version;
I want to get all distinct version stored in the db.
My attempts:
public interface MyColDao extends MongoRepository<MyCol, String>, QueryDslPredicateExecutor<MyCol> {
#Query("{ distinct : 'MyCol', key : 'version'}")
List<String> findDistinctVersion();
}
Or just findDistinctVersion without the query annotation.
Most of the examples of github have a By-field like
List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);
I don't need a By field.
Another example I found here.
#Query("{ distinct : 'channel', key : 'game'}")
public JSONArray listDistinctGames();
This doesn't seem to work for me.
I can't seem to find queryDSL/Morphia's documentation to do this.
public interface MyColDao extends MongoRepository<MyCol, String>, QueryDslPredicateExecutor<MyCol> {
#Query("{'yourdbfieldname':?0}")
List<String> findDistinctVersion(String version);
}
here version replaces your your db field name
more you can see here
This spring documentation provide the details, how to form a expression when you are want to fetch distinct values.
Link
I had a similar problem, but I couldn't work out how to do it within the MongoRepository (as far as I can tell, it's not currently possible) so ended up using MongoTemplate instead.
I believe the following would meet your requirement.
#AutoWired
MongoTemplate mongoTemplate
public List<String> getVersions(){
return mongoTemplate.findDistinct("version", MyCol.class, String.class);
}

How to use OrderBy with GreaterThan Spring JPA

I want to add in my Repository interface a method which find all the data greater than a long publishdata value and Order it Decreacingly:
I tried this, but it doesn't seems to be working:
#Repository
public interface NoticiaRepository extends CrudRepository<Noticia,Long>{
Noticia findById(long id);
List<Noticia> findByOrderPublishdateGreaterThanDesc(long publishdate);
}
List<Noticia> findByPublishdateGreaterThanOrderByPublishdateDesc(Long publishdate)

Categories

Resources