Get all columns within last month with a JPA query? - java

My current Query counts all tickets sold for each event and lists each event with the most tickets desc. Now the problem is, that I need to also get all tickets within the last month and I simply can not get the needed result from the JPArepo Doc. only.
The current query looks like this:
#Query("select t.event.id, count(t.id) from Ticket t where t.event.seat = True group by t.event.id order by count(id) desc")
I am thinking a where after the "True" and before the grouping needs to be implemented but I just dont know how.
I would be really greatful if someone of you could manage to help me out!
Edit: Forgot to mention that the current event date is simply called "date", so to access it what needs to be done is simply t.event.date.

Change your query to something like this:
#Query("select t.event.id, count(t.id) from Ticket t where t.event.seat = ?1 and t.event.date >= ?2 group by t.event.id order by count(t.id) desc")
List<?> getEventCount(Boolean seatTaken, Date eventDate);
I modified the query to have the seat be a boolean parameter (for reusability if you want to find seats that were not taken) and added in the Date parameter.
Then calculate the date a month back as such:
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MONTH, -1);
Date date = cal.getTime();
And finally implement the new method:
List<?> results = repo.getEventCount(true, date);
To create a Service class in spring and put it all together try something like:
#Service
public class TicketService {
#Autowired
private TicketRepository repo;
public List<?> getTicketEventCount() {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MONTH, -1);
Date date = cal.getTime();
List<?> results = repo.getEventCount(true, date);
return results;
}
}

Related

JPA set timestamp generated by database but not CURRENTTIME or UPDATETIME

I have a class like this
#Entity
#Table(name = "Event")
public class Event {
#Transient
public static final long MAX_TIMESTAMP = 253402214400000L; // 9999-12-31 00:00:00
private Date creationTime;
private Date expiryTime;
private String otherValue;
public Event(int timeout, String otherValue){
this.creationTime = new Date();
this.expiryTime = (timeout == 0 ? new Date(MAX_TIMESTAMP) : new Date(creationTime.getTime() + SECONDS.toMillis(timeout)));
this.otherValue = otherValue;
}
}
I call save() methed in CrudRepository and save this data.
and I have a ScheduledExecutorService to find out some timeout events:
#Query("SELECT t FROM Event t WHERE t.expiryTime < CURRENT_TIMESTAMP")
List<Event> findTimeoutEvents();
this CURRENT_TIMESTAMP is database's time, but expiryTime is not. It means that I must make their time is same.sometimes, the application and database are not in the same machine, I can not make sure their time is same.
Can I set "expiryTime" generated by database? How can I pass the parameter "timeout" to database.
the database maybe postgresql or mysql.
thank you very much.
First of all I am not sure your code works, since instance of java.util.Date (if expiry time is java.util.Date object) can not be compared to int 0.
As for generating an expiryTime, yes, you obviously can. Check out how do triggers work.
Also I would like to add, that if you use spring-boot-starter-data-jpa, you may annotate creationTime field with #CreationTimestamp annotation. But I would personally set default value to CURRENT_TIMESTAMP() on db side.

FindBy combining 'between' and 'or'

I'm already using findAllDateBetween(startD, endD) but I would like to know if I can include another date field to search for. Something like (is not working) findAllDate1BetweenOrDate2Between(startD, endD). The startD and endD are the same for Date1 and Date2. Any ideas?
This is the repository:
public interface Cert10TotalRepository extends JpaRepository<Cert10Total, Integer> {
List<Cert10Total> findByDateGermBetween(Date start, Date end);
}
I would like to add OrDatePurityBetween (Date start, Date end)
Thank you
Yes you can like this:
List<Cert10Total> findByDateGermBetweenOrDatePurityBetween(Date germStart, Date germEnd, Date purityStart, Date purityEnd);
General style is that each conjunction(between and or in your case) is appended with the param that is passed.
But in all the fairness, I think you should use a query instead as it's more readable than a such a lengthy method name and misplace param values for callers

Spring, Hibernate : Retrieve Objects based upon date, if not found, nearest date

I am working on a Spring-MVC project in which I am working on creating a backup of GroupNote object every night. Before creating a backup, I am checking if boolean flag indicating that the object was modified is true. If yes, then only a backup is created, and date is already set when the object was created.
Now, when a duplicate GroupNote object is created, it has the latest date set.
This way, the user can select a particular date and then retrieve the data-set for that day.
Now, the problem is :
If the object was not modified on Day 3,4,5, but directly on 6th, and then on 7th, once that is done, what if the User tries to retrieve the object from Day-3, it was not modified, but it was on 6th, so how I can implement this logic, where I have to retrieve the next best one.
The other problem I am facing is, GroupNotes have many-to-one mapping with GroupSection. How can I retrieve all GroupNote objects for a given GroupSection for a given date, which wont give all entities which are after Day-3, but only the 6th one.
Here is how every-night I am creating duplicates :
#Override
public void retrieveModifiedNotes() {
List<GroupNotes> groupNotesList = this.groupNotesDAO.listModifiedNotesForYesterday();
for(GroupNotes yesterdayNotes : groupNotesList){
yesterdayNotes.setLatestNote(false);
this.groupNotesDAO.editGroupNote(yesterdayNotes,yesterdayNotes.getOwnedSectionId());
GroupNotes newDayNotes = new GroupNotes();
BeanUtils.copyProperties(yesterdayNotes, newDayNotes);
newDayNotes.setLatestNote(true);
newDayNotes.setMnoticesid(0);
newDayNotes.setGroupNoteHistorySet(yesterdayNotes.getGroupNoteHistorySet());
newDayNotes.setNoteActivitySet(yesterdayNotes.getNoteActivitySet());
newDayNotes.setNoteSelectionSet(yesterdayNotes.getNoteSelectionSet());
newDayNotes.setUnreadNotesSet(null);
newDayNotes.setPrimaryNote(yesterdayNotes);
this.groupNotesDAO.addGroupNote(newDayNotes,yesterdayNotes.getOwnedSectionId());
}
}
The DAO me to get modified notes :
#Override
public List<GroupNotes> listModifiedNotesForYesterday() {
Session session = this.sessionFactory.getCurrentSession();
Calendar cal = Calendar.getInstance(); // Todays date
Query query = session.createQuery("from GroupNotes as gs where gs.noteModified=true and gs.latestNote=true and " +
"gs.noteSavedDate<:loadDate");
query.setParameter("loadDate", cal.gethodtTime());
return query.list();
}
Model GroupNotes :
#Entity
#Table(name = "groupnotes")
public class GroupNotes implements Serializable {
#Column(name = "note_modified", columnDefinition = "boolean default false")
private boolean noteModified;
#Column(name = "latest_note", columnDefinition = "boolean default true")
private boolean latestNote;
#Column(name = "note_save_date", columnDefinition = "date")
private Date noteSavedDate;
#ManyToOne
#JoinColumn(name = "msectionid")
#JsonIgnore
private GroupSection ownednotes;
}
Problematic DAO method :
#Override
#Transactional(readOnly = true)
public List<GroupNotes> listGroupNotesBySectionAndDate(int sectionId, Date dateToLoad) {
Session session = this.sessionFactory.getCurrentSession();
org.hibernate.Query query = session.createQuery("From GroupNotes as n where n.ownednotes.msectionid=:msectionid and ((n.noteDisabled=false and n.noteInActive=false "
+ "and n.privateNoteUser is null and n.noteSavedDate>:dateToLoad)) order by n.noteSavedDate asc");
query.setParameter("msectionid", sectionId);
query.setParameter("dateToLoad", dateToLoad);
return query.list();
}
As you can see in the above method, I have no way of limiting the query to only the object found on a specific date, I have a comparator operator, which will give data for any date after/before the one specified.
I hope the problem is clear, if there are any doubts, kindly let me know. Thank you. :-)
As far as I understand your problem, your dao method is perfectly fine, but you want to get only the best result (with closest date) not whole list, right?
In that case you should jpa hibernate's paging mechanism to limit the query result to only one row.
This question should be a help.

How to combine multiple date-between searches with CrudRepository of Spring Data JPA?

spring-data provides a way to generate SQL search by defining the method name.
The following works fine:
#Entity
public class Book {
Date from, to;
}
//CrudRepository<Book>
findByFromDateBetween(Date departure, Date arrival);
But why then does the following not work?
findByFromDateBetweenAndToDateBetween(Date departure, Date arrival);
To connect two date searches, I have to repeat the date:
findByFromDateBetweenAndToDateBetween(Date departure, Date arrival, Date departure, Date arrival);
Question: is it possible to reuse the params?
The Between keyword naturally binds two parameters. Thus after binding the from clause, the parameter list is exhausted and we don't know which parameters to use for the second criteria.
A manually defined query should do the trick:
interface BookRepository extends Repository<Book, Integer> {
#Query("select b from Book b " +
"where b.from between ?1 and ?2 and b.to between ?1 and ?2")
List<Book> findByDatesBetween(Date departure, Date arrival);
}

How should I store a date interval in Cassandra?

I'm working on an application that stores sensor measurements. Sometimes, the sensors will send erroneous measurements (e.g. the measured value is out of bound). We do not want to persist each measurement error separately, but we want to persist statistics about these errors, such as the sensor id, the date of the first error, the date of the last error, and other infos like the number of successive errors, which I'll omit here...
Here is a simplified version of the "ErrorStatistic" class:
package foo.bar.repository;
import org.joda.time.DateTime;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
public class ErrorStatistic {
#Nonnull
private final String sensorId;
#Nonnull
private final DateTime startDate;
#Nullable
private DateTime endDate;
public ErrorStatistic(#Nonnull String sensorId, #Nonnull DateTime startDate) {
this.sensorId = checkNotNull(sensorId);
this.startDate = checkNotNull(startDate);
this.endDate = null;
}
#Nonnull
public String getSensorId() {
return sensorId;
}
#Nonnull
public DateTime getStartDate() {
return startDate;
}
#Nullable
public DateTime getEndDate() {
return endDate;
}
public void setEndDate(#Nonnull DateTime endDate) {
this.endDate = checkNotNull(endDate);
}
}
I am currently persisting these ErrorStatistic using Hector as follows:
private void persistErrorStatistic(ErrorStatistic errorStatistic) {
Mutator<String> mutator = HFactory.createMutator(keyspace, StringSerializer.get());
String rowKey = errorStatistic.getSensorId();
String columnName = errorStatistic.getStartDate().toString(YYYY_MM_DD_FORMATTER);
byte[] value = serialize(errorStatistic);
HColumn<String, byte[]> column = HFactory.createColumn(columnName, value, StringSerializer.get(), BytesArraySerializer.get());
mutator.addInsertion(rowKey, COLUMN_FAMILY, column);
mutator.execute();
}
private static final DateTimeFormatter YYYY_MM_DD_FORMATTER = DateTimeFormat.forPattern("yyyy-MM-dd");
When we receive the first measurement in error, we create an ErrorStatistic with sensorId and startDate set, and a null endDate. This ErrorStatistic is kept in our in-memory model, and persisted in Cassandra.
We then update the ErrorStatistic in memory for the next measurements in error, until we receive a valid measurement, at which point the ErrorStatistic is persisted and removed from our in-memory model.
Cassandra thus contains ErrorStatistics with open-ended intervals (e.g. [2012-08-01T00:00Z|null]), and closed intervals (e.g. [2012-08-01T00:00Z|2013-01-12T10:23Z]).
I want to be able to query these ErrorStatistics by date.
For example, if I have these 3 error statistics:
sensorId = foo
startDate = 2012-08-01T00:00Z
endDate = 2012-09-03T02:10Z
sensorId = foo
startDate = 2012-10-04T03:12Z
endDate = 2013-02-01T12:28Z
sensorId = foo
startDate = 2013-03-05T23:22Z
endDate = null
(this means we have not received a valid measurement since 2013-03-05)
If I query Cassandra with the date:
2012-08-04T10:00Z --> it should return the first ErrorStatistic
2012-09-04T00:00Z --> it should return that there were no errors at this time
2014-01-03T00:00Z --> it should return the last ErrorStatistic (since it is open-ended)
I am not sure how I should store and "index" these ErrorStatistic objects, to efficiently query them. I am quite new to Cassandra, and I might be missing something obvious.
Edit: the following was added in response to Joost's suggestion that I should focus on the type of queries I am interested in.
I will have two types of query:
The first, as you guessed, is to list all ErrorStatistics for a given sensor and time range. This seems relatively easy. The only problem I will have, is when an ErrorStatistics starts before the time range I'm interested in (e.g. I query all errors for the months of april, and I want my query to return ErrorStatistics[2012-03-29:2012-04-02] too...)
The second query seems harder. I want to find, for a given sensor and date, the ErrorStatistics whose interval contains the given date, or whose startDate precedes the given date, with a null endDate (this means that we are still receiving errors for this sensor). I don't know how to do this efficiently. I could just load up all ErrorStatistics for the given sensor, then check the intervals in Java... But I'd like to avoid this if possible. I guess I want Cassandra to start at a given date and look backward until it finds the first ErrorStatistics with a startDate that precedes the given date (if any), then load it and check in Java if its endDate is null or after the given date. But I have no idea if that's possible, and how efficient that would be.
The question you have to ask yourself is what questions you have towards the ErrorStatistics. Cassandra schema design typically starts with a 'Table per query' approach. Don't start with the data (entities) you have, but with your questions/queries. This is a different mindset than 'traditional' rdbms design, and I found it takes some time to get used to.
For example, do you want to query the statistics per Sensor? Than a table with a composite key (sensor id, timeuuid) could be a solution. Such a table allows for quick lookup per sensor id, sorting the results based on time.
If you want to query the sensor statistics based on time only, a (composite) key with a time unit may be of more help, possibly with sharding elements to better distribute the load over nodes. Note that there is catch: range queries on primary keys are not feasible using the Cassandra random or murmur partitioners. There are other partitioners, but they easily tend to uneven load distribution in your cluster.
In short, start with the answers you want, and then work 'backwards' to your table design. With a proper schema, your code will follow.
Addition (2013-9-5): What is good to know is that Cassandra sorts data within the scope of a single partition key. That is something very useful. For example the measurements would be ordered by start_time in descending order (newest first) if you define a table as:
create table SensorByDate
(
sensor_id uuid,
start_date datetime,
end_date datetime,
measurement int
primary key (sensor_id, start_date)
)
with clustering order by (start_time DESC);
In this example the sensor_id is the partition key and determines the node this row is stored on. The start_date is the second item in the composite key and determines the sort order.
To get the first measurement after a certain start date in this table you could formulate a query like
select * from SensorByDate
where sensor_id = ? and start_date < ? limit 1

Categories