Grails minimum value fetch - grails

I am working to fetch the minimum value from a table in Grails where the vehicleid and the type is given
there are many values associated from that vehicleid and type i need to fetch the minimum date associated with that vehicleid . I have tried this but it is not working for the startDate param.
List vehicleDate= Table.createCriteria().list() {
and{
eq('vehicleid',vehicleIDGiven)
eq('type',type)
min("startDate")
}
}
what could be the query like

If you just need to fetch the minimum value, you could use a projection as documented here.
Not tested, but your criteria should look something like this:
def result = Table.createCriteria().list() {
and{
eq('vehicleid',vehicleIDGiven)
eq('type',type)
}
projections {
min("startDate")
}
}
println "Minimum start date is ${result[0]}"

Related

Attempting to map dates to index in ElasticSearch

I am using ElasticSearch and attempting to create an index with a class that has a dynamic type property in it. This property may have strings or dates in it. When indexing, I have been using the code below:
dynamic instance = MyObject.GetDynamicJson();
var indexResponse = client.Index((object) instance, i=>i
.Index("myIndex")
.Type("MyObject")
);
Here's the code for GetDynamicJson().
MyObject has only Name and Value as properties. (apologies, I've had issues in the past with Elastic choking on json without all the quotes, which I have escaped with \ characters):
String json = "{ \"Name\":\" + Name + "\",\"DateValue\":\"";
try {
var date = DateTime.parse(Value);
json += DateTime.ToString("yyyy/MM/dd HH:mm:ss Z") + "\", \"Value\":\"\"}";
} catch { //If the DateTime parse fails, DateValue is empty and I'll have text in Value
json += "\",\"Value\":\"" + Value + "\"}";
}
return json;
For some reason it doesn't seem to like the string in DateValue and I definitely don't know why it's leaving out that property entirely in the error:
For whatever reason, ElasticSearch is completely dumping the DateValue property, doesn't seem to see the DateValue property at all.
I'm getting the error:
{"name":"CreatedDate","value":"2017-11-07T13:37:11.4340238-06:00"}
[indices:data/write/bulk[s][p]]"}],"type":"class_cast_exception","reason":"org.elasticsearch.index.mapper.TextFieldMapper cannot be cast to org.elasticsearch.index.mapper.DateFieldMapper"},"status":500
Later note: I have changed the index creator method to update the mapping. I added a third field to the Object, so now it has properties: Name, Value, DateValue:
public static void CreateRecordsIndex(ElasticClient client)
{
client.CreateIndex("myIndex", i => i
.Settings(s => s
.NumberOfShards(2)
.NumberOfReplicas(0)
)
.Mappings(x => x
.Map<MyObject>(m => m.AutoMap())));
}
Now, it is successfully mapping and creating a property each time, but it still seems to drop the property I am sending it in the json. It just sets them all to the default datetime: "dateValue": "0001-01-01T00:00:00". This is strange, because when making the dynamic instance I send to Elastic, I use only the MyObject.GetDynamicJson() method to build it. I no longer get the mapping error, but Elastic still seems oblivious to "dateValue":"some date here" in the object when it is set.
OK, I got rid of the dynamic object type (ultimately I wasn't actually getting data from the json method, I had a typo and Elastic was getting the original object directly - it's a wonder it was still handling it). So I let Elastic do the parse using its mapping. In order to do that, I first updated MyObject to include multiple properties, one for each type the incoming property could be (I am only handling text and dates in this case). For the DateValue property of MyObject, I have this:
public DateTime DateValue {
get
{
try
{
return DateTime.Parse(Value);
} catch
{
return new DateTime();
}
}
set
{
try {
DateValue = value;
} catch
{
DateValue = new DateTime();
}
}
}
Now, if Value is a date, my DateValue field will be set. Otherwise it'll have the default date (a very early date "0001-01-01T00:00:00"). This way, I can later search both for text against that dynamic field, or if a date is set, I can do date and date range queries against it (technically they end up in two different fields, but coming from the same injested data).
Key to this is having the index mapping setup, as you can see in this method from the question:
public static void CreateRecordsIndex(ElasticClient client)
{
client.CreateIndex("myIndex", i => i
.Settings(s => s
.NumberOfShards(2)
.NumberOfReplicas(0)
)
.Mappings(x => x
.Map<MyObject>(m => m.AutoMap())));
}
In order to recreate the index with the updated MyObject, I did this:
if (client.IndexExists("myIndex").Exists)
{
client.DeleteIndex("myIndex");
CreateRecordsIndex(client); //Goes to the method above
}

How to apply index in descending order in grails domain class?

I have written a domain class
class ReportCallByUser {
Integer userId;
String userName;
String reportName;
Date timeOfReportCall;
static constraints = {
}
static mapping = {
timeOfReportCall index: 'time_of_report_call_index'
}
The last line creates an index in database but in ascending order. How can I create index on 'timeOfReportCall' with descending order?
Thanks in advance.
There's no such thing as order in regards to index creation. It's the query's ability to specify the ordering:
ReportCallByUser.list( [ sort:'timeOfReportCall', order:'[desc|asc]' ] )
I am assuming that you want the results in descending order by default when you query the database using GORM. If that is the case, you can specify sort order in your mapping as such.
static mapping = {
sort timeOfReportCall:"desc"
}
Hope that helps.

Grails querying model containing an enum set

My domain class is
class RoomWantedAd{
Set<MateAgeRange> mateAgeRanges
static hasMany=[mateAgeRanges :MateAgeRange]
}
Her MateAgeRange is :
enum MateAgeRange {
TWENTIES('18-29')
,THIRTIES('30-39')
,FOURTIES("40-49")
,FIFTIES("50-59")
,SIXTIES("60+")
final String value
private MateAgeRange(String value) {
this.value = value
}
String toString() { value }
String getKey() { name() }
static belongsTo=[roomWanted:RoomWanted]
}
My problem is searching. In the search page, a person can select 0 or more values in [18-29, 30-39, 40-49, 50-59, 60+]. In the db, 0 or more values among [18-29, 30-39, 40-49, 50-59, 60+] are stored in field 'mateAgeRanges'.
Let db contains [30-39, 50-59] in 'mateAgeRange' field. Let in the search page, the user selects [18-29, 50-59, 60+]. Then the Ad corresponding to the above list must be returned. This is because at least one value in user's selection is present in the db list. How is it possible. Is it possible using an SQL query or grails GORM query.
you have to use exactly the same <g:select/> tag as you are using for create/update. Thus, you will see human readable values like THIRTIES in browser, but in the background the '30-39' values will be used.

Group by week / month / year in GORM

I have a domain class (minified) as :-
class Expense {
Date dateOfExpense
int amount
}
I am trying to get sum of amount grouped by week/month/ year of expense date.
Referring to 'sqlGroupProjection' method in grails doc http://grails.org/doc/latest/guide/GORM.html,
I tried using following code:-
def results = c {
between("dateOfExpense", fromDate, toDate)
projections {
sqlGroupProjection 'dateOfExpense,sum(amount) as summed',
'MONTH(dateOfExpense)',['date','summed'],[DATE,NUMBER]
}
}
Throws exception:
No such property: DATE for class: grails.orm.HibernateCriteriaBuilder. Stacktrace follows:
Message: No such property: DATE for class: grails.orm.HibernateCriteriaBuilder
Please suggest an approach using sqlGroupProjection method
Create three new numeric fields each for week,month and year in the domain class. These fields won't be mapped to column in the table.
Provide static mapping for the three fields.
static mapping = {
//provide the exact column name of the date field
week formula('WEEK(DATE_OF_EXPENSE)')
month formula('MONTH(DATE_OF_EXPENSE)')
year formula ('YEAR(DATE_OF_EXPENSE)')
}
Now we can group by desired field using
def results = c.list {
between("dateOfExpense", fromDate, toDate)
projections {
switch(groupBy){
case "week":
groupProperty('year')
groupProperty('month')
groupProperty('week')
break;
case "month"
groupProperty('year')
groupProperty('month')
break;
case "year":
groupProperty('year')
break;
}
sum('amount')
}
}
Instead of this
static mapping = {
week formula('WEEK(DATE_OF_EXPENSE)') //provide the exact column name of the date field
month formula('MONTH(DATE_OF_EXPENSE)')
year formula ('YEAR(DATE_OF_EXPENSE)')
}
try this
static mapping = {
week formula: 'WEEK(DATE)'
month formula: 'MONTH(DATE)'
year formula: 'YEAR(DATE)'
}
Try something like
sqlGroupProjection 'MONTH(dateOfExpense) as month, sum(amount) as summed',
'month',['month','summed'],[NUMBER,NUMBER]
This sqlGroupProjection method seems to be poorly supported. Use
def results = c.list {
between("dateOfExpense", fromDate, toDate)
projections {
groupProperty('dateOfExpense')
sum('amount')
}
}
will produce the deserved outcome.
If you want group by the month of the date, see Grails group by date (It totally outweight my answer, actually. But I reach the same solution after trying your code for a long time.)

Grails group by date

I have a domain class with a date-property.
class Transaction {
LocalDate time
BigDecimal amount
}
How can I query for the sum of all transactions grouped by month? I canĀ“t find any support for group by a date-range in GORM.
Add a formula based field to your domain class for the truncated date:
class Transaction {
LocalTime time
BigDecimal amount
String timeMonth
static mapping = {
timeMonth formula: "FORMATDATETIME(time, 'yyyy-MM')" // h2 sql
//timeMonth formula: "DATE_FORMAT(time, '%Y-%m')" // mysql sql
}
}
Then you'll be able to run queries like this:
Transaction.withCriteria {
projections {
sum('amount')
groupProperty('timeMonth')
}
}

Resources