How can I use $where in spring data MongoDB? - java

I am not able to use $where in SpringDataMongoDb.
Is there any way to achieve this in SpringBoot?
db.getCollection('my_collection').find({ $where : function(){
for (var key in this.action_status){
return this.action_status[key] == false;
}
}})
Thank You.

It can be implemented in two ways one is using MongoTemplate and criteria query in spring boot application
Query query = new Query();
query.addCriteria(Criteria.where("action_status").eq(false));
List<User> users = mongoTemplate.find(query,MyCollectionClassName.class);
Another way is using mongo repository
#Query("SELECT mc FROM my_collection mc WHERE mc.status = false")
MyCollectionClassName findMyCollectionClassNameByStatus(Integer status);
References :
https://www.baeldung.com/queries-in-spring-data-mongodb
https://www.baeldung.com/spring-data-jpa-query

1: You can create a repository that extends MongoRepository and have a JSON Query method as follows:
#Query("{'action_status':{$eq:?0}}")
public List<YourObj> findByActionStatus(boolean status);
2: You can use Query By Object Attribute in MongoRepository. Supposedly you have a field called "isActionStatus" in your object, just declare this method in your repository:
public List<YourObj> findByIsActionStatus(boolean actionStatus);
Spring Data will break the method name like "select * from ... where isActionStatus = actionStatus
If you need a more complex query you can find the supported keywords here: https://docs.spring.io/spring-data/mongodb/docs/1.2.0.RELEASE/reference/html/mongo.repositories.html

Related

LIKE Query in JPA using List of String - Spring

Have used containing method in repository for %LIKE% SQL equal in JPA, as below,
Page<Obj> findByNameContaining(String name, Pageable pageable);
which will work like below,
select * from Obj where name like '%John%';
But how do i pass the List<String> names which would query like below using JPA,
select * from Obj where name like '%John%' or name like '%Jiva%' or name like 'etc' .....;
Is there any Spring JPA way for this? i also checked Specification classes too, is that the only way of doing this or am i missing any easy ways or any other dynamic query is recommended?
The most Spring Data JPA way to do this is to use a Specification which adds a like-predicate for every element in the list.
You would call it like so
repository.findAll(containingOneOf(listOfNames))
with Specification containingOneOf(List<String> listOfNames) is a method you need to create.
See https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/ for more details about specifications in Spring Data JPA.
It is not possible to create a query with multiple like operator inside a repository interface But there is a workaround to do this using EntityManager.
EntityManager is extensively used in SimpleJpaRepository. We can get instance of this class using #PersistenceContext like this:
#PersistenceContext
private EntityManager entityManager;
and call its method .createQuery(QUERY).getResultList() to execute a database call. For pagination , You can check this Pagination using entity manager in spring
To create query you can write a simple logic like this:
String createQuery(List<String> names){
StringBuilder query = new StringBuilder("select e from Employee e where ");
int size = names.size();
for(int i = 0; i < size; i++){
query.append("e.name like '%").append(names.get(i)).append("%'");
if(i != size-1){
query.append(" OR ");
}
}
return query.toString();
}
In the above code , Employee is my entity class for which i am creating a select query with multiple like operator.
Complete code:
List<Employee> getEmployees(List<String> names){
String query = createQuery(names);
return entityManager.createQuery(query).getResultList();
}

Spring data neo4j: How to append dynamic #Query?

How to generate dynamic value of #Query when have complex queries in Neo4jRepository ? Like:
#Repository
public interface StockRepository extends Neo4jRepository<StockNode,Long> {
#Query("match (n:stock) where n.name={aShareShortName} return n")
List<StockNode> getStockNodeByAShareShortName(#Param("aShareShortName") String aShareShortName);
#Query("match (n:stock) where n.{indexName}={indexContent} return n")
List<StockNode> getStockNodeByQueryProperty(#Param("indexName")String indexName,String indexContent);
}
The first method getStockNodeByAShareShortName is Ok. But the second getStockNodeByQueryProperty is failed. Is there any method to generate dynamic property keys in n.{xxx} or n.?1 or n.:xx ?
for creating dynamic property or dynamic query you need to use session(import org.neo4j.ogm.session.Session;) then you can create dynamic query and append your where condition
String query="match (n:stock) where" DYNAMIC_FIELD+"=" +VALUE
session.query(Map.class, query, queryParameters);

How to search with multiple parameters using paging and sorting repository?

I am using paging and sorting repository for jquery datatable in my spring project. I tried searching with three parameters as of now like
#Query(value = "Select p from ProfileBaseInfo p where p.fullName = :fullName or p.firstName = :firstName or p.lastName = :lastName")
Page<ProfileBaseInfo> search(#Param("fullName") String fullName,#Param("firstName") String firstName,#Param("lastName") String lastName,Pageable pageable);
Now i need to search 5 more parameters additionally with different combinations(i.e. and/or). I have generated a dynamic query based on the parameters searched. (i.e)If a parameter is present, I will join the table and insert the where condition. How do I bring the dynamically generated query inside of #Query or should I handle this in a different way? Now i what i want is I have to build a criteria like "SELECT * FROM profile where name=? and fullName=? and title=? and city=? and state=? and country=?" in ***#Query*** Annotation.
I would like to know if there is another way to do because the number of columns in a table can be high.
I think you should create a Spring bean with implementation of your search method (Spring Data).
#Autowire some bean to talk with DB (EntityManager or similar) and write down whatever query you need.
I'd recommend you to use some kind of wrapper object for all your parameters, like
class Parameters {
String firstName,
String fullName;
...
Object paramN;
<<getters-setters ?>>
}
and to use CriteriaQuery to construct query according to parameters, like
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<ProfileBaseInfo> cq = cb.createQuery(ProfileBaseInfo.class);
Root<ProfileBaseInfo> from = cq.from(ProfileBaseInfo.class);
...
List<Predicate> predicates = Lists.newArrayList();
...
if (param.getFullName() != null) {
predicates.add(cb.like(cb.lower(ProfileBaseInfo_.fullName)), param.getFullName().toLowerCase() + "%"))
}
...
cb.and(predicates.toArray(new Predicate[predicates.size()]));
So you can expand parameters list accroding to needs and there is no need to work with strings.

Spring Data JPA: How can Query return Non- Entities Objects or List of Objects?

I am using spring data JPA in my project. I am playing with millions of records. I have a requirement where I have to fetch data for various tables and build a object and then paint it on a UI. Now how to achieve this my Spring data Repositories. I have read that it can be achieved by Named native queries.
If the named native query does not return an entity or a list of
entities, we can map the query result to a correct return type by
using the #SqlResultSetMapping annotation.
But when I am trying to use #SqlResultSetMapping it is taking another entityResult. Mean what I understand is that it is just transformation some query result to entity result set only, but I want a result set of non - entities objects.
#SqlResultSetMapping(
name="studentPercentile",
entities={
#EntityResult(
entityClass=CustomStudent.class,
fields={
#FieldResult(name="id", column="ID"),
#FieldResult(name="firstName", column="FIRST_NAME"),
#FieldResult(name="lastName", column="LAST_NAME")
}
)
}
)
#NamedNativeQuery(
name="findStudentPercentile",
query="SELECT * FROM STUDENT",
resultSetMapping="studentPercentile")
In above example I am just trying to get a results from student Entity into another pojo 'CustomStudent' which is not a entity. (This example I am trying to execute just for POC purpose, actual usecase is much complicated, with complicated query returning different resultset).
How to achieve above usecase? Is there any other way besides using name query that my repository method returning Non - Entities objects?
You can do something like
#NamedQuery(name="findWhatever", query="SELECT new path.to.dto.MyDto(e.id, e.otherProperty) FROM Student e WHERE e.id = ?1")
Then the MyDto object would just need a constructor defined with the correct fields i.e.
public MyDto(String id, String otherProperty) { this.id = id; this.otherProperty = otherProperty; }
I was deeply surprised when I came accross this for the first time but, yes, you can map query results using #SqlResultSetMapping only to scalars and managed entities.
The best you can do, I guess, is to skip automatic mapping. Query without mapping would return List<Object[]> and you can map it the way you need.
Another approach would be to use #MappedSuperclass. The class denoted as #MappedSuperclass (CustomStudent in your case) can be (not sure 100%, though) used in #SqlResultSetMapping. but you need to introduce inheritance hierarchy, that is your Student entity must extend CustomStudent. That would suck most of the time from the proper OO design, because inheritance would be a little bit artificial...
How about JPA 2.1 ConstructorResult ?
#SqlResultSetMapping(
name="studentPercentile",
classes={
#ConstructorResult(
targetClass=CustomStudent.class,
columns={
#ColumnResult(name="ID"),
#ColumnResult(name="FIRST_NAME"),
#ColumnResult(name="LAST_NAME")
}
)
}
)
#NamedNativeQuery(name="findStudentPercentile", query="SELECT * FROM STUDENT", resultSetMapping="studentPercentile")
We can also parse using JSON help.
Class level declaration.
#Autowired
private EntityManager em;
private ObjectMapper mapper = new ObjectMapper();
Main Code.
Query query = em.createNativeQuery(argQueryString);
NativeQueryImpl nativeQuery = (NativeQueryImpl) query;
nativeQuery.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
List<Map<String,Object>> result = nativeQuery.getResultList();
List<CustomStudent> resultList = result.stream()
.map(o -> {
try {
return
mapper.readValue(mapper.writeValueAsString(o),CustomStudent.class);
} catch (Exception e) {
ApplicationLogger.logger.error(e.getMessage(),e);
}
return null;
}).collect(Collectors.toList());

Selecting fields on Spring Data

I'm trying to find information about how to select only certain fields of an entity using Spring Data (I'm using JPA). I want to select only specific information of an entity, the repository interfaces gives you the ways to return the information of the WHOLE entity!. Some times I only need 2 or 3 fields of an entity and returning 20,30, ...100.. fields may be a little overkill.
This kind of functionality is something that I would do using Hibernate Criteria Projections, or even JPA "SELECT NEW ...." queries. Don't know if it is possible with Spring Data.
Thanks.
What you can do is return a List<Object[]> from repository. Then in your service class iterate over this list and manually create the object you need. Sample repository method
#Query("select el.moduleId, el.threadId from ExceptionLog el")
public List<Object[]> tempQuery();
I think you can also do it in this way
SomeDataPOJO{
required col1
required col2
}
and then write query like this
#Query("select new SomeDataPOJO from requiredTable where xyz="abc")
public List<SomeDataPoJO> tempQuery()
Its not plain Spring Data but did you consider using Springs JdbcTemplate? Its also in the Context if you use Spring Boots Autoconfiguration and has several handlers for transforming results of the Query.
For Example for the Query SELECT a, b FROM EMPLOYEE WHERE ID = ? you could use
String query = "SELECT a, b FROM EMPLOYEE WHERE ID = ?";
List<Pair<String,Integer>> employees = jdbcTemplate.queryForObject(
query, new Object[] { id }, new ExampleRowMapper());
Where the ExampleRowMapper transforms each row from the result into your given Return type (Pair<String, Integer> in this case) and could look like
public class ExampleRowMapper implements RowMapper<Pair<String, Integer>> {
#Override
public Pair<String, Integer> mapRow(ResultSet rs, int rowNum) throws SQLException {
return Pair.of(rs.getString(1), rs.getString(2));
}
}
Example adapted from https://www.baeldung.com/spring-jdbc-jdbctemplate where you find more information.
Of course its not as typesafe as a JPQL as the Query is "raw" or "native" SQL but at least the response is again typesafe and I like it more than to return Object[] or something.

Categories

Resources