i have a need in which i have to return a count related to a day/week or year.
Example:
Assume i have orders which are placed on a certain date
class Order {
Date orderDate
}
How would i get an overview of the amount of orders per day / per week / per year etc?
It's untested but you need something like this:
class Order {
Date orderDate
BigDecimal amount
static namedQueries = {
summaryProojectionByDate = {
projections {
count("id", "orderCount")
sum("amount", "amountSum")
groupProperty("orderDate", "orderDate")
}
}
}
}
This groups by a specific date. I think it would be hard to group by weeks in HQL.
I just stumbled upon this blog that suggests using the new sqlProjection for Grails 2.0 and also has alternative solutions for Grails 1.x.
Related
In angular dart I have a list of transactions with a date and an ID (integer). I want to sort the list by date and within each similar date sub-sort by ID. I was able to do this by sorting by ID first and then sorting the list again by date. This seems like it is a common type of sort. Can this be done in one sort statement instead of two?
transactions.sort((a, b) => (a.id.compareTo(b.id)));
transactions.sort((a, b) => (a.transdate.compareTo(b.transdate)));
Yes it's possible
You just need to compare the date first, and if dates are the same you compare the id
transactions.sort((a, b) {
final diff = a.transdate.compareTo(b.transdate);
if (diff == 0) {
return a.id.compareTo(b.id);
}
return diff;
});
looking into Java query approach or Kotlin based DNQ can't see how to make queries similar to 'group by' ... What is a proper approach for such queries? E.g. when I have invoices entities and I would like to group these by company name and sum of sales.
Something like this can help you achieve an emulated "GROUP BY":
entityStore.executeInTransaction(
new StoreTransactionalExecutable() {
#Override
public void execute(#NotNull final StoreTransaction txn) {
txn.getEntityTypes().forEach(type -> {
EntityIterable result = txn.getAll(type);
long count = result.count();
});
}
});
Essentially what this does is it queries all entity types and then do a count, similar to what GROUP BY does. From here you can just create a Map or something to put both the entity type and count in the map.
I wish to retrieve a list of UserProfile registrations per day.
The domain object UserProfile stores a Date creationDate property.
I've tried
def results = UserProfile.executeQuery('select u.creationDate, count(u) from UserProfile as u group by u.creationDate')
println results
which obviously is not what I need because data is (already) stored with complete time in it.
Any resource savvy solution will fit: projections, hql, ...
Thnks
I use HQL cast function:
def results = UserProfile.executeQuery("""
select cast(u.creationDate as date), count(u)
from UserProfile as u
group by cast(u.creationDate as date)
""")
Underlying database must support ANSI cast(... as ...) syntax for this to work, which is the case for PostgreSQL, MySQL, Oracle, SQL Server and many other DBMSs
Break down the date to day, month and year then ignore the timestamp.
This should give you what you need.
def query =
"""
select new map(day(u.creationDate) as day,
month(u.creationDate) as month,
year(u.creationDate) as year,
count(u) as count)
from UserProfile as u
group by day(u.creationDate),
month(u.creationDate),
year(u.creationDate)
"""
//If you do not worry about dates any more then this should be enough
def results = UserProfile.executeQuery( query )
//Or create date string which can be parsed later
def refinedresults =
results.collect { [ "$it.year-$it.month-$it.day" : it.count ] }
//Or parse it right here
def refinedresults =
results.collect {
[ Date.parse( 'yyyy-MM-dd', "$it.year-$it.month-$it.day" ) : it.count ]
}
You could define a "derived" property mapped as a formula to extract the date part of the date-and-time. The exact formula will differ depending what DB you're using, for MySQL you could use something like
Date creationDay // not sure exactly what type this needs to be, it may need
// to be java.sql.Date instead of java.util.Date
static mapping = {
creationDay formula: 'DATE(creation_date)'
}
(the formula uses DB column names rather than GORM property names). Now you can group by creationDay instead of by creationDate and it should do what you need.
Or instead of a "date" you could use separate fields for year, month and day as suggested in the other answer, and I think those functions are valid in H2 as well as MySQL.
Following are my two classes
class Users {
String emailAddress
String password
// String filename
String firstName
String lastName
Date dateCreated
Date lastUpdated
}
and
class SharedDocuments {
Users author
Users receiver
Documents file
static constraints = {
}
}
I want to run a query similar to this one, essentially i want to get list of all the users along with count of documents they have authored
SELECT author_id, COUNT(SharedDocuments.id )FROM SharedDocuments
INNER JOIN users ON author_id = users.id
GROUP BY author_id
This is what I have so far
def sharedDocumentsInstanceList = SharedDocuments.createCriteria().list(params){
createAlias("author","a")
eq("receiver.id",session.uid)
projections{
groupProperty "author"
count "id",'mycount'
}
order('mycount','desc')
maxResults(params.max)
}
I have this 90% working, if i get rid of count or countDistinct I get list of distinct authors but what i want is authors along with the counts of documents. So when i add the count or countDistinct clause to this criteria I just get array of long!!
like [2,3,4] what I want is [[author1,2],[author2,3] ...]
How can i achive this I have already seen Grails: Projection on many tables?,
Grails criteria projections - get rows count,
Grails groupProperty and order. How it works?,
but none of the answers seem to be solving my issue!
Projections with pagination has a bug where it only return the last field in the projections block. The current grails 2.1.5 has this bug fixed. Here is the reported bug http://jira.grails.org/browse/GRAILS-9644
Couldn't you just use countBy* - like
SharedDocuments.countByAuthorAndReceiver(user, receiver)
If you want the result as as you described in your query then you need the id of the author or any other specific property like email.
def sharedDocumentsInstanceList = SharedDocuments.createCriteria().list(params){
eq("receiver.id",session.uid)
projections{
groupProperty "author"
count "id",'mycount'
}
order('mycount','desc')
maxResults(params.max)
}
I have a domain class Schedule with a property 'days' holding comma separated values like '2,5,6,8,9'.
Class Schedule {
String days
...
}
Schedule schedule1 = new Schedule(days :'2,5,6,8,9')
schedule1.save()
Schedule schedule2 = new Schedule(days :'1,5,9,13')
schedule2.save()
I need to get the list of the schedules having any day from the given list say [2,8,11].
Output: [schedule1]
How do I write the criteria query or HQL for the same. We can prefix & suffix the days with comma like ',2,5,6,8,9,' if that helps.
Thanks,
Hope you have a good reason for such denormalization - otherwise it would be better to save the list to a child table.
Otherwise, querying would be complicated. Like:
def days = [2,8,11]
// note to check for empty days
Schedule.withCriteria {
days.each { day ->
or {
like('username', "$day,%") // starts with "$day"
like('username', "%,$day,%")
like('username', "%,$day") // ends with "$day"
}
}
}
In MySQL there is a SET datatype and FIND_IN_SET function, but I've never used that with Grails. Some databases have support for standard SQL2003 ARRAY datatype for storing arrays in a field. It's possible to map them using hibernate usertypes (which are supported in Grails).
If you are using MySQL, FIND_IN_SET query should work with the Criteria API sqlRestriction:
http://grails.org/doc/latest/api/grails/orm/HibernateCriteriaBuilder.html#sqlRestriction(java.lang.String)
Using SET+FIND_IN_SET makes the queries a bit more efficient than like queries if you care about performance and have a real requirement to do denormalization.