Is there a way to get a list ordered by two fields, say last and first names?
I know .listOrderByLastAndFirst and .list(sort:'last, first') won't work.
Hates_ criteria answer didn't seem to work for me; putting "last,first" in order will only cause exceptions saying, "Property 'last,first' not found". To order on two fields, you can do the following:
def c = MyDomain.createCriteria()
def results = c.list {
and{
order('last','desc')
order('first','desc')
}
}
This is quite old but helped me in finding a suitable solution. A "cleaner" code example by using withCriteria shortcut:
def c = MyDomain.withCriteria {
and {
order('last', 'desc')
order('first', 'desc')
}
}
This old solution no longer works. Please see mattlary's answer below
You may have to write a custom finder in HQL or use the Criteria Builder.
MyDomain.find("from Domain as d order by last,first desc")
Or
def c = MyDomain.createCriteria()
def results = c.list {
order("last,first", "desc")
}
More complicated ordering criteria, (tested in Grails 2.1.0)
def c = MyDomain.withCriteria {
property {
order('last', 'desc')
}
order('first', 'desc')
}
sorts first by MyDomain.property.last then by MyDomain.first
MyDomain.findAll(sort: ['first': 'desc','last':'desc'])
works with grails-datastore-gorm:6.0.3
I think a criteria is the best bet, but you did the right thing by attempting a finder first. When retrieving domain objects from GORM, the right order to make the attempt is: dynamic finder, criteria, HQL.
This query is working on the basis of first field. When the first field is blank then it is shorted by the second field.
order('last','desc')
order('first','desc')
you can do this
def results=MyDomain.findAll([sort:"last",order:'desc'],[sort:"first",order:'desc']);
this line of code will first sort results from domain class "MyDomain" first by last name and then by first name of the person .
If you were sorting lists on the contents of their items, you would need to implement a comparator which would have some smarts to enable to you decide the sort order based on multiple properties.
Some examples of Groovy-style comparators are shown here
However if the list you are sorting is being returned from a database query, you would be better off sorting it using a CrteriaQuery and sorts on that
I has the same problem.
Since my list is not so big, I use groovy sort, as I want to sort on fields of linked domain:
CalendarData -> Attraction
def listCalendar (Calendar calendar) {
respond CalendarData.where {
calendar == calendar
}.list().sort{ "$it.attraction.type?:' '$it.attraction.name" }
}
Related
So I have a list:
def list = [1,2,3,...]
And then I have a list of objects from the database:
def loo = findAllBySomeField()
And for each object in the list, if field A on that object doesn't match anything in the first list, then I want to add field B on the object to another list. What's the best way to do this without having a bunch of .each and .collect closures? I've looked into intersect() and removeAll() but it seems there's no clean and simple way to do this.
Also is there a findAllBySomeFieldNotInList()? It seems grails only has the InList dynamic method but no NotInList().
createCriteria().list() {
not {
inList 'someField', unwantedValues
}
projections {
property 'fieldB' // or distinct instead of property
}
}
should do
I have two object, a room type and a reservation. Simplified they are:
class Room {
String description
int quantity
}
class Reservation {
String who
Room room
}
I want to query for all rooms along with the number of rooms available for each type. In SQL this does what I want:
select id, quantity, occupied, quantity-coalesce(occupied, 0) as available
from room left join(select room_id, count(room_id) as occupied from reservation)
on id = room_id;
I'm not getting anywhere trying to work out how to do this with HQL.
I'd appreciate any pointers since it seems like I'm missing something fairly fundamental in either HQL or GORM.
The problem here is your trying to represent fields that are not your domain classes like available and occupied. Trying to get HQL\GORM to do this can be a bit a little frustrating, but not impossible. I think you have a couple options here...
1.) Build your domain classes so that there easier to use. Maybe your Room needs to know about it's Reservations via a mapping table or, perhaps write what you want the code to look like and then adjust the design.
For example. Maybe you want your code to look like this...
RoomReservation.queryAllByRoomAndDateBetween(room, arrivalDate, departureDate);
Then you would implement it like this...
class RoomReservation{
...
def queryAllByRoomAndDateBetween(def room, Date arrivalDate, Date departureDate){
return RoomReservation.withCriteria {
eq('room', room)
and {
between('departureDate', arrivalDate, departureDate)
}
}
}
2.) My second thought is... It's okay to use the database for what it's good for. Sometimes using sql in you code is simply the most effective way to do something. Just do it in moderation and keep it centralized and unit tested. I don't suggest you use this approach because you query isn't that complex, but it is an option. I use stored procedures for things like 'dashboard view's' that query millions of objects for summary data.
class Room{
...
def queryReservations(){
def sql = new Sql(dataSoruce);
return sql.call("{call GetReservations(?)}", [this.id]) //<-- stored procedure.
}
}
I'm not sure how you can describe a left join with a subquery in HQL. INn any case you can easily execute raw SQL in grails too, if HQL is not expressive enough:
in your service, inject the dataSource and create a groovy.sql.Sql instance
def dataSource
[...]
def sql= new Sql(dataSource)
sql.eachRow("...."){row->
[...]
}
I know it's very annoying when people try to patronize you into their way of thinking when you ask a question, instead of answering your question or just shut up, but in my opinion, this query is sufficiently complex that I would create a concept for this number in my data structure, perhaps an Availability table associated to the Room, which would keep count not only of the quantity but also of the occupied value.
This is instead of computing it every time you need it.
Just my $.02 just ignore it if it annoys you.
I would like to use the .list call with another query (for example a date range or all of a certain type). Is this possible or do I need to build a custom .find call wrapping all the options in .list like offset and max?
You'll probably want to look at the Dynamic Finders and/or Where Queries sections of the Grails doc. If you want to give a more specific example of what you're trying to accomplish I can better answer your questions.
You can try something like:
filter = { it.datePublished >= 'date1' && it.datePublished <= 'date2' }
def filteredList = Book.list(max: 10, offset: 100).collect(filter)
Let's say I have a domain class called "User" which can follow other "User" objects. It does so having a field specified as:
def hasMany=[followedUsers:User]
I need to do the reverse (find all User objects that follow a specific User object) without setting up the reverse relationship, since it is not a use case performed often. I tried to do something like this, using closures:
User.findAll { it.followedUsers.contains(userInstance) }
but this always returns all users in the database, regardless of their follow status. I tried doing with HQL but failed miserably as well.
Could anyone give me a quick pointer on the simplest way to accomplish this? Thank you.
You can use this HQL query:
User.executeQuery(
'select u from User u where :follower in elements(u.followedUsers)',
[follower: userInstance])
In my opinion, this syntax is much cleaner:
User.withCriteria { followedUsers{ eq('id', userInstance.id) } }
I need a help with what I believe is very trivial stuff.
class User {
String name
static hasMany = [files : File]
}
class File {
long size
}
Now when I need the total size of all files a given user has I use the following which is working :
def user = User.get(id)
user.files.each(total+=it.size)
but how ugly is it, when I am sure it can be done with simple select sum query with either plain SQL or GORM/CRITERIA
I have tried something like File.sumBySize..()
Or
def c = File.createCriteria()
def f = c.list{
eq("user", user) // What here ?
projections
{
sum("size")
}
}
I dont know how to specify the parent(user) relationship which is not defined in File class but in Grails join tables
Any help appreciated
Why is that ugly? It only takes 1 statement (with no SQL at all) to sum up all the file sizes. Though if you want, you may be able to use HQL like so:
def user = User.get(id)
def sum = File.executeQuery("select sum(f.size) from File f where f.user = ?", user);
But I think you'd need to add a belongsTo to File to do that. There's probably a simpler HQL/GORM method that's just not coming to my mind at the moment, but honestly, I don't think there's anything easier than what you already did.
You can do it with an HQL query, but it has a small problem with the name of the 'size' field
(appears to be a reserved word). If you rename it to 'length', 'fileSize', etc. then this will work:
User.executeQuery(
'select sum(file.length) from User u join u.files file where u.id=:userId',
[userId: id])[0]
A more elegant way to sum the file sizes in Groovy code is:
def total = user.files.sum {it.size}
But if you can calculate the file size totals in the query that returns the users, that's the way I'd do it.