I have an entity which contains the data for the run - date, distance, duration and some additional:
#Entity
class RunEntry {
private Long id;
private LocalDate date;
private int weekNo;
private Long distance;
private Duration duration;
private Long userId;
// getters, setters
}
Based on this data I have to create a report which will contain per week distance and average speed (that's why I added weekNo column to easily group by):
class AverageWeekRun {
private LocalDate weekStart;
private LocalDate weekEnd;
private BigDecimal averageSpeed;
private Long distance;
// getters, setters
}
To achieve this I create a Spring Data JPA projection which contains weekNo, sum of distance and sum of duration:
interface RunPerWeek {
int getWeekNo();
Long getSumOfDistance();
Long getSumOfDuration();
}
and I created a simple method in repository:
#Query("select r.weekNo as weekNo, sum(r.distance) as sumOfDistance, sum(r.duration) as sumOfDuration "
+ "from RunEntry r where r.userId = :userId group by r.weekNo")
Page<RunPerWeek> findRunPerWeekForUser(Long userId, Pageable pageable)
It works fine, I can use this query result and map it to AverageWeekRun (by calculating the week start/end based on weekNo and average speed based on sum of distance and sum of duration).
However, I want to use sort from pageable to order by average speed or by week start or week end date. These fields are calculate so I get an exception when I try to pass it with sort. How can it be solved? I want the user to use field names from AverageWeekRun class but some of them are calculated and Spring Data JPA cannot handle it.
You can use:
Sort sort = Sort.by(Sort.Direction.DESC, "sumOfDistance");
Pageable pageable = PageRequest.of(page, limit, sort);
I have used it, as long as your calculated value has "as somename", this will work.
Related
I'm trying to get the list of distinct items by a specific field (userId). Currently I'm using this kind of approach to get records from MongoDB using ReactiveCrudRepository. Additionally, I want this result to be further filtered and get only the distinct items.
How to do this?
#Query(value = "{$and :[{'submitTime':{$ne:null}}, {'gameId': :#{#gameId}} ]}", sort = "{'score': -1, 'timeTaken': 1, 'submitTime': 1}")
Flux<Play> getWinners(#Param("gameId") String gameId, Pageable pageable);
My Play object is like this:
#Document(value = "play")
#Builder
public class Play {
#Id
private String id;
private String gameId;
private int score;
private String userId;
private LocalDateTime submitTime;
private long timeTaken;
}
At the moment #Query annotation doesn't provide a possibility to execute the distinct command.
As a workaround you can
implement a custom method with find, sort and distinct actions
use .distinct() operator after calling your repo method getWinners() to distinct items by key selector, but in this case this operation will not be performed in MongoDB
I want to select columns based on my input (List < String >)
#Entity
#Table
public class Product {
#Id
private Long id;
private String name;
private String price;
}
I understand that to select distinct specific columns, I can use #Query("SELECT DISTINCT name FROM TABLE")
However, I want to give users the flexibility to select the columns they want. e.g. List < String > columns = Arrays.asList(["name", "price"]). This will then select distinct from both name and price columns.
For this create a custom method implementation and use one of the following (or of the many variants thereof)
construct a SQL or JPQL query using String concatenation (be careful not to introduce SQL injection vulnerabilities).
use some kind of criteria API like
JPA Criteria API
Querydsl
JOOQ
From the List of Orders, i need to collect dates which are past to requesteffDate and requesteffTime and take the maximum of the past dates.
function boolean dateCheck(Date effdt, Date efftm) {
String efffdt = new SimpleDateFormat("yyyyMMdd").format(effdt);
String effftm = new SimpleDateFormat("HHmm").format(efftm);
Date effdttm = new SimpleDateFormat("yyyyMMddHHmm").parse(efffdt + "" + effftm);
return effdttm.before(new Date());
}
rule "finding past maximum date"
when
$company : Company( $date:requesteffDate, $time:requesteffTime, $reqdt : requesteffDate.getTime(), $reqtm : requesteffTime.getTime() )
eval(dateCheck($date,$time))
accumulate(Orders( effectiveDate != null,
effdate:effectiveDate.getTime()<$reqdt),
maxEffDate:max(effdate))
then
//error
While doing this,
accumulate(Orders(effectiveDate!=null,
effdate:effectiveDate.getTime()<$reqdt),
maxEffDate:max(effdate))
I am getting maxEffDate as -9223372036854775808 which when converted is showing 1940
Same I have tried using min functionn it is showing 2262.
My class goes like this.
Class Company{
private Date requesteffDate;
private Date requesteffTime;
private Employee emp;
private List<Orders> orderlist;
}
Class Orders{
private Date effectiveDate;
private Date effectiveTime;
}
-9223372036854775808 is Long.MIN_VALUE. This is conclusive for indicating that the accumulate doesn't find any Orders.
Make sure that you insert some matching Orders facts.
Add a guard that the maxEffDate is != Long.MIN_VALUE.
Discontinue the usage of Date as a time-of-day value: Either use LocalDate and LocalTime or combine date and time into a single Date value.
Take care that conversions of date and time are not affected by your locale settings.
I want to find the Results based on Mongo NamedQuery
#Document(collection="test")
#Getter
#Setter
public class TestData {
#Id
private String name;
private String fiscalWeek;
private String fiscalYear;
}
Here fisaclWeek in the range of 1 to 52
#Query("'fiscalWeek' : {$gt : ?0, $lt : ?1}}")
List<TestData> findByDateRange(String fromDate, String toDate);
here fromDate and toDate will come like this 512015 that means concatenation of week and year
I tried like the above way but need to concatenate fisaclWeek and fisaclYear but not sure how to concatenate in the #Query method
How to write a Query here so that I will get results in the range of fromDate and toDate?
Can anyone help on this.
public List<Series> findSeries(int period, String fieldname, int num) {
TypedQuery<Series> query = em.createQuery(
"select s from Series s where s.period = ?1 order by ?2",
Series.class);
query.setParameter(1, period);
query.setParameter(2, fieldname);
query.setMaxResults(num);
return query.getResultList();
}
This is the method I am using. I think order by isn't even getting executed, it doesn't give any error even when I pass incorrect fieldname.
When it comes to dynamic limit and ordering, its best to use PagingAndSortingRepository so now my Repository extends this repository. I can simply use JPA criteria query as below.
If u want to learn more about JPA criteria query i found this very helpful http://docs.spring.io/spring-data/data-jpa/docs/1.0.x/reference/html/#jpa.query-methods.query-creation
#Repository
public interface SeriesRepository extends PagingAndSortingRepository<Series,Long>{
List<Series> findByPeriod(int period, Pageable pageable);
}
And then when I call this method from my dao i can just instantiate PageRequest which is one of the implementation of Pageable. I can add limit and sorting order to this instance.
public List<Series> getSeriesByFilter(int period, String fieldname, int num) {
Sort sort = new Sort(Sort.Direction.ASC, fieldname);
Pageable pageable = new PageRequest(0, num, sort);
return seriesRepo.findByPeriod(period, pageable);
}
You cannot pass variables as column name in order by.
There is a work around which may help you achieve what you are trying.
public List<Series> findSeries(int period, String fieldname, int num) {
String query = "select s from Series s where s.period = "+period+" order by "+fieldname;
return entityManager.createQuery(query).getResultList();
}
Check this question Hibernate Named Query Order By parameter
There are ways to pass column name in order by in ASP, however I am not able to find anything in Spring or JPA.
"Order By" using a parameter for the column name
http://databases.aspfaq.com/database/how-do-i-use-a-variable-in-an-order-by-clause.html