Closed matissg closed 6 years ago
I'd appreciate if anyone could clear out if it's possible to achieve search by data within JSONB column? In my example I have JSONB column data
where I want to search by ptype
values.
Can you please try with the master branch of the repo?
@matissg it seams master branch is okay. https://github.com/jbox-web/ajax-datatables-rails/blob/master/lib/ajax-datatables-rails/datatable/column.rb#L46
you will recieve 2 params column
and formated_value
@ajahongir @n-rodriguez Thank you, I updated from master branch.
Now I get error ArgumentError (wrong number of arguments (given 2, expected 1))
and it points to my find_ptype
, which looks like in example above.
What am I doing wrong?
The lambda waits for 2 params :
def find_ptype
-> (column, formatted_value) { where("positions.data->>'ptype' like ?", "#{ptype}%")}
end
you will recieve 2 params column and formated_value
@n-rodriguez dont you think this feature shoud be in 0.4 branch?
@ajahongir : yes, I'm doing some checks before releasing a v0.4.1
@n-rodriguez Thank you.
I assumed I shouldn't be using "#{ptype}%"
since my find_ptype
doesn't know what it is, so I'm trying to do this:
def find_ptype
-> (column, formated_value) { where("positions.data->>'ptype' like ?", "#{formated_value}%") }
end
but now I get NoMethodError (undefined method "where" for
and it points to my find_ptype
above.
Update
def find_ptype
-> (column, formatted_value) { where("positions.data->>'ptype' like ?", "#{ptype}%")}
end
gives me this error: NameError (undefined local variable or method "ptype"
@ajahongir Thank you, but I can't make it to work. I even tried this one, which was in another answer for JSON column:
def find_ptype
->(column) { Arel.sql("JSON_EXTRACT(#{column.field}, '$.ptype')") }
end
but it's not working as well.
whats is wrong with your case?
@ajahongir Well, I have this error ArgumentError (wrong number of arguments (given 2, expected 1))
when I do e.g. ->(column) { column.table[column.field].eq(column.search.value.to_i + 1) }
Basically I'm trying to filter records by drop-down string value of my ptype
column. I can access it with Position.data->>'ptype'
and my data
is JSONB column.
def find_ptype
->(column, formatted_value) {
Arel.sql("JSON_EXTRACT(#{column.field}, '$.ptype') = #{formatted_value}")
}
end
I think it should look like this.
@ajahongir Ok, I got this error:
ActiveRecord::StatementInvalid (PG::SyntaxError: ERROR: syntax error at or near "column"
LINE 1: ... NULL AND (JSON_EXTRACT(data->>'ptype', '$.ptype') = column)
how should look like your right sql query?
.. AND (JSON_EXTRACT(data->>'ptype', '$.ptype') = pilon)
- like this?
I could retrieve all "billboards" from "ptype" with this one:
SELECT * FROM positions WHERE data->>'ptype' = 'billboard';
I would need to pass in my desired ptype
string value and get out filtered records.
def find_ptype
->(column, formatted_value) {
Arel.sql("JSON_EXTRACT(#{column.field}, '$.ptype') = '#{formatted_value}'")
}
end
how about this?
Got this error:
ActiveRecord::StatementInvalid (PG::UndefinedFunction: ERROR: function json_extract(text, unknown) does not exist
LINE 1: ...ND "positions"."deleted_at" IS NULL AND (JSON_EXTRA...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
: SELECT COUNT(*) FROM "positions" WHERE "positions"."type" IN ('Position::Outdoor') AND "positions"."deleted_at" IS NULL AND (JSON_EXTRACT(data->>'ptype', '$.ptype') = 'billboard')):
@ajahongir In my model I have this scope:
scope :pilons, -> {
where("position_positions.data->>'ptype' = :pilon", pilon: "pilon")
}
and then the query looks like this:
[3] pry(main)> Position::Outdoor.pilons.take(1)
Position::Outdoor Load (2.9ms) SELECT "positions".* FROM "positions" WHERE "positions"."type" IN ('Position::Outdoor') AND "positions"."deleted_at" IS NULL AND (positions.data->>'ptype' = 'pilon') LIMIT $1 [["LIMIT", 1]]
As you see this part allows me to get my ptype
values: (positions.data->>'ptype' = 'pilon')
Do you have any other ideas of how should I change this?
Arel.sql("JSON_EXTRACT(#{column.field}, '$.ptype') = '#{formatted_value}'")
@ajahongir @n-rodriguez Looks like the solution in my case is like this:
->(column, formatted_value) { Arel.sql("positions.#{column.field} = '#{formatted_value}'") }
I needed to add my table name before column and it seems it wasn't about JSON_EXTRACT
I hope this helps for someone else, maybe you can add this to gem's docs, so people can do filtering by JSONB column values. It might be quite cool in some cases. Thank you for helping!
Update
If anyone needs here is how to do ILIKE search for JSONB column:
def find_address
->(column, formated_value) {
Arel.sql("positions.data->>'address'").matches("%#{formated_value}%")
}
end
Query looks like this: AND (positions.data->>'address' ILIKE '%Optio%')
In this example I do search in my positions
table JSONB column data
by address
value, which in this exaple is "Optio".
Notice. Don't forget to add indexes for your JSONB column keys - otherwise queries will be slow.
maybe you can add this to gem's docs, so people can do filtering by JSONB column values
Done! https://github.com/jbox-web/ajax-datatables-rails#tutorial
Thank you!
Thanks for the helpful thread. I ran into this myself and built upon this to find a cond function which may be more general. I have numerous fields in JSON.
My cond filter
def my_filter
->(column,formatted_value) { Arel.sql(column.field.to_s).matches("%#{formatted_value}%")}
end
With this, I can define my view columns with whatever Postgres JSON magic needed. ajax-datatables-rails will just pass that magic as a string to the cond filter which will build the right SQL. Without this, the default behavior was that the magic was quoted as a single string in SQL, which gave a non-existent column error.
My view_columns
def view_columns
@view_columns ||= {
id: { source: "Volunteer.id"},
first_name: { source: "Volunteer.data->>'given_name'", cond: my_filter,orderable: true},
last_name: { source: "Volunteer.data->>'family_name'", orderable: true, cond: my_filter},
email: { source: "Volunteer.data->>'email_addresses'", orderable: true, cond: my_filter},
}
end
I have
positions
table, where there is JSONB columndata
. I'm trying to search for values ofptype
inside thatdata
column.At the moment I can do sorting for
ptype
, however search is not working and I get this error:NoMethodError (undefined method "field" for "pilon":String):
when I search for "pillon" in myptype
field.My
ajax-datatables-rails
file looks like this:Search for my
name
column is working just fine since it's regular table column.For custom search I tried to copy idea from this example. How do I fix my search for JSONB column data, please?