Rails - Querying a JSON Field - ruby-on-rails

In my Rails 5 app, I'm using the Ahoy gem which uses a jsonb field (called properties) that I don't know how to query.
A sample of the data in the properties field:
"{\"id\":\"11\"}"
What I'm trying to do is:
Find the records created in the last seven days (using the time field)
Group the records by the id in the properties field
Order the records based on which id had the most records
I tried this:
#foo = Ahoy::Event.where(name: "Viewed Product").where(time: 7.days.ago..Time.now).group("properties(id)").order('COUNT("properties(id)") DESC')
but I received the error, PG::UndefinedColumn: ERROR: column "properties(id)" doe not exist
I found this somewhat similar question in the issues for the gem, so I tried breaking the query into parts:
#foo = Ahoy::Event.where(name: "Viewed Product").where(time: 7.days.ago..Time.now)
#foo.group("properties REGEXP '[{,]\"id\"...).count
but then my IDE gives the error unterminated string meets the end of file.
Can someone please help me determine what I'm doing wrong?

If you are using PostgreSQL, I believe that you would have to refer to json columns like this:
.group("properties ->> 'id'")

Related

ActiveRecord update error - illegal zero-length identifier

I'm running simple Rails + ActiveRecord program, where I want to take records from the database, where column "transfered_at" is null, and update it with the current time.
orders_ora = Orders.where(transfered_at: nil)
orders_ora.each do |order_ora|
puts order_ora.name
order_ora.update(transfered_at: Time.now)
end
However, it does not allow me to do that. Here is the error that I'm getting:
OCIError: ORA-01741: illegal zero-length identifier: UPDATE
"ORDERS" SET "TRANSFERED_AT" = :a1 WHERE
"ORDERS"."" IS NULL (ActiveRecord::StatementInvalid)
What am I missing?
Edit: I need to use this inside the loop because I'm doing other calculations inside it. And time format does not seems to be the problem, because I'm trying to update another column which type is "number", and I'm getting the same error.
If I try to do it like this:
order_ora.inspection_id = 333
order_ora.save
it also gives the same error as before.
Why do you loop through the results? You can do it in a single query:
Orders.where(transfered_at: nil).update(transfered_at: Time.now)
What could be a problem is that the Time.now is not in the correct format for your table? Use strftime in that case:
Orders.where(transfered_at: nil).update(transfered_at: Time.now.strftime('%H:%M') )
I found answer to this myself, it was not related to the code.
The problem was that my table did not have a PK, and it looks like ActiveRecords uses it to generate SQL statements.

rails, postgres and jsonb. query doesn't find records

I can't get my query to find relevant records.
here's my test record:
model: Submission
column name: contents (jsonb)
record is created by: Submission.create(contents: {ada: 'ada'})
here's the query: Submission.where("contents->>'ada'='ada'").first
results is nil
record is in database and (lets assume record id=1)
Submission.find(1).contents[:ada]=='ada'
results in true
Try following, ref this
Submission.where('contents #> ?', {ada: 'ada'}.to_json)
Ok, so I'm still not exactly sure what's going on but the problem was in the fact that I was assigning a default values of {} in my migration. when this default assignment is removed everything works as expected.

active record how do I specify a column after a join?

I'm trying to make an sql query using activerecord and I'm having a hard time specifying a specific column from multiple joined tables.
for instance in sql
select go.id, sequence.name, sequence.id from sequence join (goterms,...) on ...
this is not beautiful sql but my point is that I'm able to specify which .id I want returned
in activerecord I'm doing this:
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa)
.select(:header,:taxaclass, :genus, :interpro_desc,:description,:dbname,:read_depth, :name)
.distinct
I want to be able to get id from :Goterm but :Taxa and :Foreigndb also use id as a column in the database so i'm getting uninformative errors that I assume stem from this issue when I do the following.
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa)
.select(:header,:taxaclass, :genus, :interpro_desc,:description,:dbname,:read_depth, :name,:id)
.distinct
What is the correct way to just specify that I want Goterm.id?
edit - Here is the error:
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'Goterm.id' in 'field list'
when I run:
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa).select(:header,:taxaclass,:genus, :interpro_desc,:description,:dbname, :read_depth, :name,'Goterm.id').limit(5).offset(0).dresults = Sequence.joins(:Foreigndb,:Goterm,:Taxa).select(:header,:taxaclass, :genus, :interpro_desc,:description,:dbname, :read_depth, :name,'Goterm.id').limit(5).offset(0).distinct
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa).select(:header,:taxaclass, :genus, :interpro_desc,:description,:dbname,:read_depth, :name, 'sequences.id')
.distinct
It turns out that ilan's answer is correct, however be sure that everything is lower case. I was using 'Goterm.id' to make the selection when it needs to be 'goterm.id'
If anyone else runs into this, I also ran into difficulties grabbing the goterm.id data out of the returned query objects. Each time I called object.id on that return set it would give me something different from what I was expecting. I think the attribute I was expecting was being obscured by something else. To get the data I needed I did the following:
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa).select(:header,:taxaclass, :genus,:interpro_desc,:description,:dbname,:read_depth, :name).distinct
firstRes = results[0]
firstRes.attributes['id']

Rails / ActiveRecord: How to quote protected column name using #select in custom query?

Running Rails 4.0.13 with TinyTDS connected to Microsoft SQL Server 2012, I'm trying to run the following query:
sql = Model.where(:foo => bar).select(:open, :high, :low, :close).to_sql
Model.connection.execute(sql)
The problem is, the generated sql is
"SELECT open, high, low, close FROM [models]"
Which gives me an error as the column names open and close are protected.
TinyTds::Error: Incorrect syntax near the keyword 'open'
If I use #pluck, I can see the correct SQL is generated (with column names escaped):
"SELECT [models].[open], [models].[high], [models].[low], [models].[close] FROM [models]"
However, this produces an array, which is not what I want.
My question is how can i get #select to correctly quote the column names?
Thank you
I don't think you can make the select method to protect your column names when using symbols (maybe because different DBMS use different quoting identifiers), but you could pass your selection as a string :
sql = Model.where(:foo => bar).select("[open], [high], [low], [close]").to_sql
Model.connection.execute(sql)
I attempted to submit a bug report to Rails, however in doing so I saw the problem did not appear to exists using SQLite test case, this leads me to believe the issue is with the SQL Server Adapter.
Since I am on Rails 4 and not the latest version of the adapter I left it and wrote the following (horrible) method as wrapping the column names was not enough, I needed to prefix the table to prevent ambiguous column names. Yuck
def self.quote(*columns, klass)
columns.map { |col| "[#{klass.table_name}].[#{col}]" }.join(', ')
end

ActiveRecord error converting rails app from Sqlite to PostgreSQL

I moved my app from sqlite to postgresql so that I could use RGeo and PostGIS. I deleted all the data in my database and started from scratch. Everything is working fine except one particular area of the site. I have an association that links Tourstops and Venues that appears to be not working. No code was modified in this area since the switch. Unfortunately I'm still sort of new to rails and don't know enough to diagnose this error.
The error I'm getting is:
ActiveRecord::StatementInvalid in ToursController#show
PG::DatatypeMismatch: ERROR: argument of WHERE must be type boolean, not type integer LINE 1: SELECT "venues".* FROM "venues" WHERE (1) LIMIT 1 ^ : SELECT "venues".* FROM "venues" WHERE (1) LIMIT 1
def show
#tour = Tour.find(params[:id])
#tourstop = Venue.find_by(params[:id])
end
Parameters: {"id"=>"1"}
Your problem, as stated in the comments, that you're using find_by without any :key in the hash
To be clear, ActiveRecord should be able to translate between SQLite & PGSQL, so the difference has to be with your use of the ActiveRecord methods:
find
Finds individual element by primary_key:
Model.find(id)
find_by
Finds by value other than primary_key:
Model.find_by name: "Rich"
Model.find_by({name: "Rich"})

Resources