Using SQL function as a group by field in datamapper (ruby) - ruby

I'm trying to use a slightly more interesting GROUP BY cause than what seems to be supported out of the box by DataMapper.
The query I want to generate looks something like this:
SELECT SUM(downloads), SUM(uploads) FROM daily_stats GROUP BY YEARWEEK(date)
I'd like to be able to just tell DataMapper something along these lines:
DailyStat.aggregate(:downloads.sum, :uploads.sum, :fields => [ :date.yearweek ])
Where would I begin? Is this easily achievable?

I would very much like the same thing, unfortunately dm-aggregates isn't written in a manner which makes this possible.
My recommendation is to drop down into SQL since you're receiving sums from your table.
DataMapper.repository.adapter.select('SELECT SUM(downloads), SUM(uploads) FROM daily_stats GROUP BY YEARWEEK(date)')
That should give you an array of structs with the summed downloads and uploads.

Related

column "likes.id" must appear in the GROUP BY clause or be used in an aggregate function

So I am trying to add top posts functionality for my Sinatra project using postgresql with the following statement Like.group(:exercise_id).order('COUNT(exercise_id) DESC').each do |like|
But when I try this I get an error saying column "likes.id" must appear in the GROUP BY clause or be used in an aggregate function
And when I add this
Like.group(:exercise_id, :id).order('COUNT(exercise_id) DESC')
It gives me the whole table when all I want is to group by likes. Is there a workaround for this?
What the error is telling you, is that you're selecting for "likes.id", but there is no single likes.id that the database can give you.
This is because by default when you don't tell Rails what you need, Rails will select EVERYTHING.
Think, do you actually need "likes.id"? Looks to me that you're grouping by exercise_id so what you're trying to get is exercises and their like counts. (correct me if I'm wrong.) You don't actually need specific like id-s.
If that's so, we need to tell rails about our intention.
Like.group(:exercise_id).order('COUNT(exercise_id) DESC').select(:exercise_id)
If you also need the count itself, just add it to the select.
Something else you might want to try is just .count. It's pretty smart and will respect your grouping. See if this helps.
Like.group(:exercise_id).count

Calling PostGIS functions within Ruby

I need to execute the PostGIS function st_intersection within an SQL SELECT clause in Ruby. At the moment I am doing it as raw SQL query:
sql_query = "SELECT id, ST_ASEWKT(ST_INTERSECTION(geometry, ?)) FROM trips WHERE status='active';"
intersections = Trip.execute_sql(sql_query, self[:geometry].to_s)
This way has the disadvantage that I receive the result as text and I need to parse the objects out of the strings. Much nicer would be the use of the ActiveRecord interface to make queries. However, I could not find any solution yet to run PostGIS functions (e.g. st_intersection) within ActiveRecord.
An earlier version of the activerecord-postgis-adapter's README showed a nice example using the gem squeel:
my_polygon = get_my_polygon # Obtain the polygon as an RGeo geometry
MySpatialTable.where{st_intersects(lonlat, my_polygon)}.first
As this is not part of the current README anymore, I am wondering whether this is not recommended or if there are any better alternatives.
There are two problems to solve here.
The first is using an SQL function within a .select clause. Ordinarily this is pretty easy—you just use AS to give the result a name. Here's an example from the ActiveRecord Rails Guide:
Order.select("date(created_at) as ordered_date, sum(price) as total_price").group("date(created_at)")
The resulting Order objects would have ordered_date and total_price attributes.
This brings us to the second problem, which is that Rails doesn't give us an easy way to parameterize a select (i.e. use a ? placeholder), so (as far as I can tell) you'll need to do it yourself with sanitize_sql_array:
sql_for_select_intersection = sanitize_sql_array([
"ST_ASEWKT(ST_INTERSECTION(geometry, ?)) AS intersection",
geometry,
])
This will return a sanitized SQL fragment like ST_ASEWKT(ST_INTERSECTION(geometry, '...')), which you can then use to specify a field in select:
Trip.where(status: "active").select(:id, sql_for_select_intersection))
The resulting query will return Trip objects with id and intersection attributes.

Combining multiple tables with r.union in RethinkDB

I will be dynamically combining a range of tables with the exact same structure in RethinkDB.
I have my dynamically-generated list of tables in an array as follows:
tables = [r.table('table1'), r.table('table2'), ...]
And I am trying to do this:
r.union(r.args(tables))
But that just gives me an error: ReqlLogicError: Expected type DATUM but found TABLE
Overall, I have not been able to find a way to generate a list of tables in JavaScript and to add use r.union to combine them into a stream. Would appreciate help on this.
Thanks!
You can use reduce to do what you want, we merge one by one, like r.table(t1).union(r.table(t2)).union(r.table(t3)).
Like this:
[r.table('t1'), r.table('t2'), r.table('t3')].reduce(function(p, c) {
return p.union(c)
})
Try it from data explorer.
The answer provided by kureikain works. I still wish the functionality existed in RethinkDB with r.args() (it seems to me that this would be consistent with the documentation of that function).
Moreover, one important tip tangentially related to this question: if you want to combine multiple tables into a stream through r.union() but be able to tell which table it is in the results, use merge(). So my query would look something like this:
[r.db('database').table('table1').merge({source: 'table1'}), r.db('database').table('table2').merge({source: 'table2'})].reduce(function(p, c) { return p.union(c) }).filter( ...)
This allows you to not only combine multiple tables into one stream, but to always distinguish between the source tables in your results (by looking up the value of the key 'source').

Does hsqldb provide a function similar to listagg?

I am looking for a function (or a group of functions) in HSQLDB that does something similar to Oracle's LISTAGG.
I have this as part of a larger select and would like to keep the syntax as similar as possible in HSQLDB:
SELECT LISTAGG(owner_nm, ', ') WITHIN GROUP (ORDER BY owner_nm)
FROM OWNERSHIP WHERE FK_BIZ_ID = BIZ.BIZ_DATA_ID) AS CURRENT_OWNER
The point of this is that we're trying to use HSQLDB for remote work and Oracle for working on site, prod, etc so I want to change the DDLs as little as possible to achieve that.
Looking at ARRAY_AGG, it doesn't seem like it does anything similar (as far as being able to pull from a separate table like we're doing above with OWNERSHIP). Any suggestions for how I may accomplish this?
group_concat is probably what you are looking for:
http://www.hsqldb.org/doc/2.0/guide/dataaccess-chapt.html#dac_aggregate_funcs
Quote from the manual:
GROUP_CONCAT is a specialised function derived from ARRAY_AGG. This function computes the array in the same way as ARRAY_AGG, removes all the NULL elements, then returns a string that is a concatenation of the elements of the array

Possible to order search results using current_user

I'm trying to order search results using an equation that uses Products and User has inputs. In other words, I have an equation that uses data from both Products and current_user. I want to be able to order my search results by the number I get from the equation. I'm pretty lost on even were to begin with this. Has anyone done something similar or have any ideas of how to best handle the sort/order? From my understanding, "order" is usually used to sort actual columns in the SQL database and not a method.
I was originally thinking I would need to pass the current_user into the model. I know that's not best practice, but Sunspot allows you to create custom fields in the model and then sort on those fields. Unfortunately, this doesn't work since sunspot needs to index the fields it searches and sorts by.
I'm currently using Sunspot and would like to keep using it even if need to make modifications. I'm also using pagination.
You cannot calculate complex equations in SQL. You are restricted to simple calculations.
Possible Solutions:
Depending on how many results you get it might be possible to just
use the ruby sort method.
Calculate the result of your equation and store them in a new
column or table
Your problem could be associated with "matching".

Resources