0

I have a jsonb "contacts" field in a table which is:

  1. An object, where each key is the contact type such as mailing, billing, emergency etc. These are loosely defined.
  2. The value for each key in #1 is an array containing 1 or more contacts for each type
  3. Each value inside #2 is an object containing loosely defined fields.

Example:

  {
  "main": [{
    "name": "Bobby Smith",
    "email": "[email protected]", 
    "telephone": "555-999-0000"
  }, {
    "name": "Joan Smith",
    "email": "[email protected]", 
    "telephone": "555-999-0002"
  }],
  "billing": [{
    "name": null,
    "region": "Arizona",
    "address": ["PO BOX 123", "456 Nowhere Road"],
    "country": "USA",
    "locality": "BigMac",
    "postalCode": "90210"
  }],
  "emergency": [{
    "name": "John Cooper",
    "email": "[email protected]",
    "telephone": "555-987-0000"
  }]
}   

I'd like to have a simple way to do a comparison on say the name fields that is agnostic to the keys in the outermost object, as well as the number of elements in each array.

Effectively this: SELECT * FROM clients WHERE contacts#>>'{*, *, name}' = 'John Cooper';

Would return the row containing the above as it matches '{emergency, 0, name}'

1 Answer 1

2

You need to unwind data for your current database design, like:

select t.*
from   t, jsonb_each(contacts) e, jsonb_array_elements(e.value) c
where  c ->> 'name' = 'John Cooper'

But this can't use any index for your query.

A better design would be to only store contact data on each row in a joining table, like:

  t                  t_contact
------------------  -------------------------
 t_id primary key    t_id references t(t_id)
                     contact_type text
                     contact jsonb

Then, you could index t_contact(contact) and query, like:

select   t.*
from     t
join     t_contact using (t_id)
where    contact ->> 'name' = 'John Cooper'
group by t.t_id
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.