Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I search within an JSON array of hashes by hash values?

I am using Postgres' JSON data type to store some information.

For example I have model User with a field locations that holds a json document(array of objects containing pairs of keys and values) in the following format:

[{"name": "Location 1", kind: "house"},
 {"name": "Location 2", kind: "house"},
 {"name": "Location 3", kind: "office"},
 ...
 {"name": "Location X", kind: "house"}
]

I want to query with .where on the JSON data type.

I want to query for users that have at least one location with kind = office.

Thanks!

like image 985
mamantoha Avatar asked Oct 06 '16 12:10

mamantoha


People also ask

What is a hash in JSON?

Referring to JSON dictionaries as hash tables would be technically incorrect, however, as there is no particular data structure implementation associated with the JSON data itself. A hash is a random looking number which is generated from a piece of data and always the same for the same input.

What is hash array?

An array of hashes is useful when you have a bunch of records that you'd like to access sequentially, and each record itself contains key/value pairs. Arrays of hashes are used less frequently than the other structures in this chapter.

Is a JSON object a hash table?

The Theory of JSON Standard objects are either a single key and value, or else a collection of keys and values which are equivalent to a hash table in most languages (learn about hash tables in Lua).


5 Answers

I have used a mix of above answers. This is my working code:

User.where("locations::jsonb @> ?", [{kind: 'office'}].to_json)

As a note, locations is a JSON column of User table (not JSONB datatype)

like image 170
sequielo Avatar answered Oct 04 '22 18:10

sequielo


I want to query for users that have locations with kind office

# if locations is jsonb type
User.where('locations @> ?', { kind: 'office' }.to_json)
# if locations is json type
User.where("locations->>'kind' = 'office'")
# if locations is array of hashes
User.where('locations @> ?', [{ kind: 'office' }].to_json)
like image 25
Andrey Deineko Avatar answered Oct 04 '22 18:10

Andrey Deineko


Filters based on the values of objects inside array JSONB

If you want to make filters based on the values of the objects (jsonb) inside the arrays in Rails with postgres you can use something like example below.

Assuming you have a Product model:

Product.select("*").from(
  Product.select("*, jsonb_array_elements(registers) as register")
).where("(register ->> 'price')::numeric >= 1.50")

In above example we select all products with price greater than or equal 1.50.

For this we use:

  • jsonb_array_elements() from postgres;
  • an auxiliary column and alias;
  • and methods from ActiveRecord from Rails.

I applied ident in sub-query just for best readability.

After you can put this in a scope or use other best practice.

like image 43
Jonatas Eduardo Avatar answered Oct 04 '22 17:10

Jonatas Eduardo


Source: https://www.postgresql.org/docs/current/static/functions-json.html

User.where("name::jsonb -> 'location' ->> 'kind' = ?", 'office')
like image 26
Harsimar Sandhu Avatar answered Oct 04 '22 18:10

Harsimar Sandhu


Just to give my two cents:

I have a model with a JSON with a key and an array inside, so it looks like this:

ModelObj: attribute: { key: [val0, val1, val2, val3] }

I needed to find all objects with, for example, attributes where the key has val3 in the array. I changed my attribute type to jsonb and this was how I find it:

Model.where('attribute @> ?', {key: ['val3']}.to_json)

Maybe it's useful to someone out there.

like image 35
R. Siqueira Avatar answered Oct 04 '22 18:10

R. Siqueira