I'm trying to figure out how to sort on multiple fields in Grails 3, one of which may or may not be null. I have this Book domain:
class Book {
String title
String sortTitle
static constraints = {
title blank: false
sortTitle nullable: true
}
}
Books with titles like "The Peripheral" have a sortTitle of "Peripheral, The", otherwise sortTitle will be null. I want books sorted by sortTitle if one exists, otherwise by title.
I found other similar SO questions, but none with a nullable field. Does anyone happen to have some pointers in the right direction?
You can use:
coalesce(book.sortTitle, book.title)
Here you have the official Hibernate documentation.
I'm not 100% sure on this but it seems to me that sorting by coalesce would lead to the database doing a file sort which could be rather expensive rather than being able to make use of an index.
My suggestion would be to always populate sortTitle with the name you want to sort by and then just use that.
I couldn't quite figure out how to do it purely with GORM, but some raw HQL worked:
def books = Book.findAll("from Book as b order by coalesce(b.sortTitle, b.title)")
Related
I have a PFObject subclass which stores an array of strings as one of its properties. I would like to query for all objects of this class where one or more of these strings start with a provided substring.
An example might help:
I have a Person class which stores a firstName and lastName. I would like to submit a PFQuery that searches for Person objects that match on name. Specifically, a person should be be considered a match if if any ‘component’ of either the first or last name start with the provided search term.
For example, the name "Mary Beth Smith-Jones" should be considered a match for beth and bet, but not eth.
To assist with this, I have a beforeSave trigger for the Person class that breaks down the person's first and last names into separate components (and also lowercases them). This means that my "Mary Beth Smith-Jones" record looks like this:
firstName: “Mary Beth”
lastName: “Smith-Jones”
searchTerms: [“mary”, “beth”, “smith”, “jones”]
The closest I can get is to use whereKey:EqualTo which will actually return matches when run against an array:
let query = Person.query()
query?.whereKey(“searchTerms”, equalTo: “beth”)
query?.findObjectsInBackgroundWithBlock({ (places, error) -> Void in
//Mary Beth is retuned successfully
})
However, this only matches on full string equality; query?.whereKey(“searchTerms”, equalTo: “bet”) does not return the record in question.
I suppose I could explode the names and store all possible sequential components as search terms (b,e,t,h,be,et,th,bet,etc,beth, etc) but that is far from scalable.
Any suggestions for pulling these records from Parse? I am open to changing my approach if necessary.
Have you tried whereKey:hasPrefix: for this? I am not sure if this can be used on array values.
https://parse.com/docs/ios/guide#queries-queries-on-string-values
I have a POGO we'll call Foo and it has a list of Bars. In the database, these are simple integers, but they're stored in a separate table (Foo_Bars)
class Foo {
String name
...
static hasMany = [bars:Integer]
...
}
So my question is, how do I create a query to find all Foos that with bars that are in a list. I know how I would write it in SQL.
SELECT * FROM foo, foo_bars
WHERE foo.id = foo_bars.foo_id
AND foo_bars.bars_integer IN (11, 15, 52)
But I figure there must be a simpler way, using GORM or HQL. How would I write this?
but what exactly you want to achieve? list of Foo's where bars is equal to (11,15,52), or ONE OF bars is in the list or the list of bars contain each of given list?
either way, I doubt you can do it in criteria or using a dynamic finder, I'm trying to do it in an unit test and nothing worked
I would go with creating another domain class like
class FooBar {
Foo foo
Integer integer
}
which would create exactly the same database table as you already have, and then querying would be much simpler
i've seen in grails doc something about join fetch :
"This works well for single-ended associations, but you need to be
careful with one-to-manys. Queries will work as you'd expect right up
to the moment you add a limit to the number of results you want. At
that point, you will likely end up with fewer results than you were
expecting. The reason for this is quite technical but ultimately the
problem arises from GORM using a left outer join."
i don't see why a left outer join can raise a problem in a none single-end association like one-to-many for example.
can you give me an example ?
if i take the example given by Joshua
Class Person {
String name
static hasMany = [numbers:PhoneNumber]
static mapping = {
nubmers fetch : 'join'
}
}
Class PhoneNumber{
static belongsTo = [owner : Person]
}
//for testing
def person = Person.get(1)
result in:
select name,... from
person left outer join phone_number
on person.id = phone_number.owner_id
where person.id=1;
Can you give me a query(in gorm) which can show me the problem ?
thanks
If I understand your question correctly then it's easiest to explain with a simple example. Let's say we have a domain class Person with many PhoneNumber classes associated with it. Thus a LEFT JOIN to fetch this data will result in a SQL result like this:
PersonId, Name, PhoneNumberId, TelNumber
-----------------------------------------
1, Joe, 1, 123-123-1234
1, Joe, 2, 222-222-2222
1, Joe, 3, 333-333-3333
2, Jane, 4, 000-000-000
This would be four records returned from the datasource, but only two instances of the Person domain with their associated phone numbers. However, if you limit this query to a maximum of 2 records you will in fact only get one instance of the Person domain (Joe in this example) and his first two phone numbers.
Hope that helps you understand the underlying issue.
P.S. This is an entirely theoretical example, the actual query results from GORM would have different column names and such due to Hibernate.
Update
An example GORM based query is quite simple to demonstrate:
def people = Person.list([max: 2])
You might expect the above to give you two person instances, but in reality because of the left join you will only end up with one instance. Turning on SQL logging will show you the actual query being executed and you will notice it's using a LEFT join.
I have a domain class called Order and that class has hasMany relation with Item class.
When I am querying for the list of orders with certain restrictions I am getting as many instances of Order as there are items.
So for example Order instance has say references to 3 instances of Item then , criteria call on Order is returning 3 duplicate instances of Order. I am not sure but if it's worth mentioning that the domain class Order has fetchMode set to "eager".
I am really puzzled with what's going on there. Any help in this regard will be greatly appreciated. Snippet of code is attached:
def clazz = "cust.Order"
def criteria = clazz.createCriteria()
println("clazz == "+Order.list())// returning correct data i.e unique instance of order
def filter = {
// trimmed down all filtering criteria for debugging
}//close filter
List results = criteria.list(max:params?.max,offset:params?.offset,filter)
results.each{Object data->
println(data.getClass())
}
println("results == "+results)
Thanks again
One solution is to use this inside your query:
resultTransformer org.hibernate.Criteria.DISTINCT_ROOT_ENTITY
If you call criteria.listDistinct instead of criteria.list duplicates will be eliminated
Criteria API is just a wrapper for constructing a SQL query. In your case, the query in question has JOINs in it (because of the eager fetching), and returns a cartesian product of Orders and their matching Items. Each row returned is included in results as a separate Order instance.
The easiest way to remove duplicates is to put all the results in a Set, like this:
def resultSet = new HashSet()
resultSet.addAll(results)
println("results == " + resultSet)
You could also use dynamic finders, as in Order.findAllBy* .Depending on how complicated your filter is, this could be easy or tough :)
I have an XML file which is split up using pipes "|". I have some code in a question class that splits up the XML files "Items" as so..
List<string> questionComponents = newquestionString.Split('|').ToList<string>();
questionString = questionComponents[0];
apple = questionComponents[1];
pear = questionComponents[2];
orange = questionComponents[3];
correctAnswer = Int32.Parse(questionComponents[4]);
I want to compare these components with objects which are instantiated in my Game1 class (three fruit - apple, pear, orange). So how do I do this?
A friend helped me get this far. I have no idea how to do this, and after searching google with no luck I've resulted in asking here to you lovely people.
Thanks in advance :D
EDIT: To clear things up...
I have three objects called apple, pear and orange and I want to associate these objects with the strings which are shown in the XML file for each component of the strings. The question string displays a question, [1] answer 1, [2] answer 2, [3] answer [3].
And then I need a way to compare the answer to the object that is eaten in the game..
Assuming you have some kind of Orange object, some kind of Pear object, and some kind of Apple object, in each class override the ToString method.
If you have some generic Fruit or Answer object, consider passing a string in the constructor and returning that string in the ToString method.
EDIT: Since you've now clarified, I would go with Jonathan's idea of having a Name or Answer property; then you can do:
if(object.Answer == questionComponent)
//do stuff
And ToString does not turn the object into a string. It simply returns a user-defined (if you choose to override) string for the object - for the Ints it is "42", and for bools it is "true" or "false". No conversion occurs.
Based on your edit, it sounds like all you're trying to do is be able to look up some concrete object based on a string that you get from a data file? Couldn't you use a Dictionary for this, as in:
Fruit apple = new Apple();
Fruit orange = new Orange();
Dictionary<string,Fruit> map = new Dictionary<string,Fruit>();
map["apple"] = apple;
map["orange"] = orange;
and then later you can get the user's answer/input:
string input = ...
Fruit result;
if(map.TryGetValue(input, out result)) {
// `fruit` now holds the fruit object the user selected.
} else {
// User input did not correspond to a known fruit.
}
But I'm still not convinced I'm understanding your question properly.
It looks like the range of possible strings is limited, so why not just use identifiers in the form of Enums, which you can parse from the string, and set that identifier into the answers and the fruits?
public enum AnswerType
{
Apple,
Pear,
Banana
}
Store the answers in a dictionary mapping ids to answers (casting enum to int for the key), plus the correct answer's id, and now you can know which answer was picked each time, checking the eaten fruit's id, and if the answer was right.