Help with Creating Models for Views - grails

I am trying to create a Model to pass to a gsp view. I would like to do a sub query across two tables. I have two domains, alum_profile and alum_position. alum_profile has many alum_position's. alum_position belongs to alum_profile. In SQL if I wanted to create a result set, I would have something like this:
Select count(id),
(Select CONCAT(first_name, ' ', last_name)
From alum_profile
where
alum_profile_id =alum_profile.id ) as Person
FROM alum_position
GROUP BY alum_profile_id
ORDER BY count(id) DESC
How do I do this with HQL and create a model that can be passed to a gsp View.
Thanks for your help
jason
I am using Spring Source, with MySQL and writing in groovy on grails

From what I've read of your question, you want to display a list of the Profile's names, along with how many Positions each Profile has, sorted by the number of positions, desc.
First, you need Models:
class AlumProfile {
String first_name
String last_name
def hasMany = [positions: AlumPosition]
};
class AlumPosition {
String name // I just added this, no idea what you need in here
def belongsTo=AlumProfile
};
Now you want to create a list of the AlumProfiles sorted by position count. In your controller, you need:
def allByPositionCount = {
def profiles = AlumProfile.list().sort( [compare: { a,b -> a.positions.size().compareTo( b.positions.size() ) }] as Comparator );
[ profiles: profiles ]
}
This will render the allByPositionCount.gsp with the model containing the "profiles" member that is the list of profiles in the correct order, so something like:
<g:each in="${profiles}" var="profile" >
${profile.first_name} ${profile.last_name} has ${profiles.positions.size()} positions
</g:each>
should render what you want.

Related

Rails distinct values of a value returned by a method in model

Suppose I have an Employee model, there is a method in Employee model named def fixed
def fixed
return self.cached_fixed.to_f if self.cached_fixed.present?
return (self.current_salary && self.current_salary.fixed).to_f
end
end
def current_salary
return #current_salary if #current_salary
# #current_salary = self.employee_salaries.detect{|es| es.end_date == nil}
#current_salary = self.db_current_salary
return #current_salary
end
if the fixed were a column in employee table we could have just used Employee.distinct.select(:fixed) to pull the distinct values
is there a way if it's just a method not a field in table without loading all the employees.
I am expecting to get the unique values of a column from a table , but it may not be a column as in the above table
Not for an arbitrary method, no. But you start the query from the EmployeeSalary end and fetch only the column you care about in one query using select:
EmployeeSalary
.select(:fixed)
.join(:employee)
.where(end_date: nil)
This will run a select fixed from... query and return a list of EmployeeSalary objects, but all the fields that aren't listed in the select call will be nil. Assuming the constraint of only one salary record having end_date: nil, there will be one EmployeeSalary object per employee. You can add .distinct in the method chain if you want unique values.
I'm not sure how the caching logic fits into this question. You can apply caching logic on top of that list if you like, but doing one query like this is pretty fast.

How to iterate over object list in reverse order in Grails?

From a list of GORM database objects that are ordered desc in my user domain model I want to order them asc (i.e., in reverse order in the view). For example to get the latest books of a user from the database, but insert them in the Dom in reverse order where the latest book comes last.
How do I perform a reverse each in my GSP?
Controller:
def books = user.books
GSP:
<g:each in="${books}" var="book">${book}</g:each>
You can use default sort for relation collection as described here. So if you define like this:
class User {
…
static hasMany = [books: Book]
static mapping = {
books sort: 'publishDate', order: 'asc'
}
}
The collection will be sorted on database level
<g:each in="${books.reverse()}" var="book">${book}</g:each>
EDIT
Got carried away :). I would rather suggest:
def books = user.books?.reverse() in controller.
(Separation of concern, view should not have logic of manipulating model)
UPDATE:
In case books are not ordered in User, explicit sorting is required.
def newestBooks = user.books?.asList().sort{it.publishDate}
to reverse sort use
def newestBooks = user.books?.asList().sort{-it.publishDate}

How Do I Use Joins for Three Tables in Ruby on Rails?

I am working on a Ruby on Rails application which already has logic for text searching using pg_search and two other fields on a model. The logic creates an 'array' of rows from the search result. I do not remember the actual name of this since technically this is not an array. It is an instance variable of selected rows. I want to add search criteria from two additional models. My database is PostgreSQL.
Here is a subset of all three model definitions:
MediaLibrary: name, media_creator_id, media_type_id (fields that are being used in current search; has many media_topics and has many media_targets)
MediaTopic: media_library_id, topic_id (want to search for topic_id; belongs to media_library; topic_id being searched is coming from a Topic model (id, name))
MediaTarget: media_library_id, target_id (want to search for target_id; belongs to media_library; target_id being searched is coming from a Target model (id, name))
I'm thinking that I should be able to do something like this if both topic and target are being searched along with the other three search criteria. I will also need to have topic_id and target_id in my results so I can display Topic.name and Target.name on my view.
#media_libraries = MediaLibrary.text_search(params[:query]).where("media_creator_id = ? AND media_type_id = ?", params[:media_creator_id].to_i, params[:media_type_id].to_i).joins(:media_topics.where("media_library_id = ? and topic_id = ?", id_from_media_library_row, params[:topic_id].to_i).joins(:media_targets.where("media_library_id = ? and target_id = ?", id_from_media_library_row, params[:target_id].to_i)
I have searched on postgresql.org and Stack Overflow but have not found anything joining three tables using Ruby on Rails that was answered by anyone.
You can pass a SQL join statement into #joins. I'm not sure what it'd be in your case but you can do something like:
#media_libraries = MediaLibrary.joins(%q(
JOIN media_targets
ON media_targets.media_library_id = media_libraries.id
JOIN media_topics
ON media_topics.media_library_id = media_libraries.id
)).text_search(params[:query])
.where(
media_libraries: {
media_creator_id: params[:media_creator_id],
media_type_id: params[:media_type_id]
},
media_topics: { id: params[:topic_id] },
)

Filtering on multiple associations and optional where clauses

I've got a several domain classes, with some simple associations between them as follows:
class Business {
String name
City city
Industry industry
}
class City {
String name
}
class Industry {
String name
}
In my application, I would like to have a "filter" where the list of all businesses can be filtered according to the City and Industry. I am able to get the City and Industry id's from the filter back to the Business controller, however, when I get to the controller to do the filtering, I have this code:
...
def industry = Industry.get(params.int('industryid'))
def city = City.get(params.int('cityid'))
def businessList = Business.findAllByIndustryAndCity(industry, city)
...
This code works when both the City and Industry fields have values. However, sometimes the user might want to just filter by city or industry and not both. In this case, the filter fails, as when either of the values are null no results are returned. How could I specify that if either of the association values are "null", then the "find" query should remove this constraint altogether? i.e. match "all" for that field
Note that I realise that it would be easy to put an if statement checking whether the values are null and then executing a different "find" statement based on that. However, while this would work with two values, I don't think it would scale well as more filterable values are added.
You can build criteria.
def c = Business.createCriteria()
def results = c.list{
and {
if (industry) {
eq("industry", industry)
}
if (city) {
eq("city", city)
}
}
}
Check reference here in grails docs.
However your code needs N+1 queries for N parameters. Maybe you can reduce it to one query using criteria idea? If your Business entity holds foreign keys to both Industry and City this one should work:
def c = Business.createCriteria()
def results = c.list{
and {
if (params.industryid) {
eq("industry_id", params.industryId as Long)
}
if (params.cityid) {
eq("city_id", params.cityid as Long)
}
}
}
Both examples are untested but you should get the idea.

Select of hasMany mapping with GORM in Grails

Suppose I have a setup like the following:
class User {
static hasMany = [items : Item];
}
class Item {
String name;
}
I'm trying to select all Users that have an Item in that hasMany mapping. I have an id of an Item, and want to find all users that “have” that item.
Is there a HQL query I can run that will do this or better yet, a built in GORM function that handles this query?
Supposing this were straight SQL I would do something like:
SELECT `user_id` FROM `user_item` WHERE `item_id`=[ID]
Looking in H2 I can write the query
SELECT USER_ID FROM USER_ITEM WHERE ITEM_ID=1;
I can expand this SQL to include the entire user object:
SELECT * FROM user, user_item WHERE user_item.item_id=[item id] AND user.id = user_user.user_items_id;
This HQL will work:
Item item = ...
Item.executeQuery(
'from User u where :item in elements(u.items)',
[item: item])

Resources