Say I have in Postgres stored in JSON field called “data” like this
{
"CUSTA": {
"name": "Customer A",
},
"CUSTB": {
"name": "Customer B",
},
"CUSTC": {
"name": "Customer C",
}
}
How can I query to return the record that contains the key “CUSTA” ? or even better the value of “CUSTA” which is "name": "Customer A"
trying to do something like this but obviously i cant use the keyword key
SELECT * FROM invoices WHERE data->>key = 'CUSTA';
select '{
"CUSTA": {
"name": "Customer A"
},
"CUSTB": {
"name": "Customer B"
},
"CUSTC": {
"name": "Customer C"
}
}'::json#>>'{CUSTA}';
?column?
------------------------------
{ +
"name": "Customer A"+
}
(1 row)
note: you have trailing commas after name:customer x, which is not proper json. For your query, you would probably do something like:
select data#>>'{CUSTA}' from invoices;
or, if data isn't already a json field:
select data::json#>>'{CUSTA}' from invoices;
I don't understand why any invoice would have more than one customer though.
-g
Related
I have the return of a json in the children column of the table. How can I loop over the title values present in the children column?
Example of JSON present in a table row.
[
{
"id": "5CBDE9F2-5D81-4CA9-8302-0908104558D9",
"title": "Title 1",
"Code": "5874"},
{
"id": "9BFC4A6C-9BDC-4C15-B01F-5B87683AE50F",
"title": "Title 2",
"Code": "6582"
}
]
I know using the [key] doesn't work. But like [0] or [2] I get it. How can I interact?
SELECT *
FROM vwJSONFilhos A
WHERE json_value(Filhos,'$[key].title') = 'Title 2'
I have a select query witch returns me an array_to_json object. I want to filters the results of select based on specifics keys and values.
Here is my actual query:
select jsonarray
from (
SELECT body.id_user,
array_to_json(array_agg(row_to_json(body))) as jsonarray
FROM (
SELECT id_user, name, value
FROM table_1
group by id_user, name, value
) body
group by body.id_user
) as test;
It returns a lot of rows like this:
[{"id_user": 1489, "name": "name 1", "value": "value aaaaaa"}, {"id_user": 1489, "name": "name 2", "value": "value babababab"}]
[{ "id_user": 1490, "name": "name 12", "value": "value aaaaaa" }, { "id_user": 1490, "name": "name 2", "value": "value babababab" }]
[ { "id_user": 1491, "name": "name 13", "value": "value aaaaaa" }, { "id_user": 1491, "name": "name 23", "value": "value uouououo" }]
Well, I want only the rows that have the fields "name": "name 2", "value": "value babababab" into the json... I've tried
select jsonarray->'name'
from (
....
) as test
where jsonarray->>'name'::text = 'name 2';
but it returns nothing. There's another way to query it?
You can check if name 2 is present during the aggregation:
SELECT jsonb_agg(to_jsonb(body)) as jsonarray
FROM (
SELECT DISTINCT id_user, name, value
FROM table_1
) body
group by body.id_user
having bool_or(name = 'name 2') -- those with at least one `name = 'name 2'`
Online example
I am constructing an interface between a PostgreSQL system and a SQL Server system and am attempting to "flatten" the structure of the JSON data to facilitate this. I'm very experienced in SQL Server but I'm new to both PostgreSQL and JSON.
The JSON contains essentially two types of structure: those of type "text" or "textarea" where the value I want is in an object named value (the first two cases below) and those of type "select" where the value object points to an id object in a lower-level options array (the third case below).
{
"baseGroupId": {
"fields": [
{
"id": "1f53",
"name": "Location",
"type": "text",
"options": [],
"value": "Over the rainbow"
},
{
"id": "b547",
"name": "Description",
"type": "textarea",
"options": [],
"value": "A place of wonderful discovery"
},
{
"id": "c12f",
"name": "Assessment",
"type": "select",
"options": [
{
"id": "e5fd",
"name": "0"
},
{
"id": "e970",
"name": "1"
},
{
"id": "0ff4",
"name": "2"
},
{
"id": "2db3",
"name": "3"
},
{
"id": "241f",
"name": "4"
},
{
"id": "3f52",
"name": "5"
}
],
"value": "241f"
}
]
}
}
Those with a sharp eye will see that the value of the last value object "241f" can also be seen within the options array against one of the id objects. When nested like this I need to extract the value of the corresponding name, in this case "4".
The JSON-formatted information is in table customfield field textvalue. It's datatype is text but I'm coercing it to json. I was originally getting array set errors when trying to apply the criteria in a WHERE clause and then I read about using a LATERAL subquery instead. It now runs but returns all the options, not just the one matching the value.
I'm afraid I couldn't get an SQL Fiddle working to reproduce my results, but I would really appreciate an examination of my query to see if the problem can be spotted.
with cte_custombundledfields as
(
select
textvalue
, cfname
, json_array_elements(textvalue::json -> 'baseGroupId'->'fields') ->> 'name' as name
, json_array_elements(textvalue::json -> 'baseGroupId'->'fields') ->> 'value' as value
, json_array_elements(textvalue::json -> 'baseGroupId'->'fields') ->> 'type' as type
from
customfield
)
, cte_custombundledfieldsoptions as
(
select *
, json_array_elements(json_array_elements(textvalue::json -> 'baseGroupId'->'fields') -> 'options') ->> 'name' as value2
from
cte_custombundledfields x
, LATERAL json_array_elements(x.textvalue::json -> 'baseGroupId'->'fields') y
, LATERAL json_array_elements(y -> 'options') z
where
type = 'select'
and z ->> 'id' = x.value
)
select *
from
cte_custombundledfieldsoptions
I posted a much-simplified rewrite of this question which was answered by Bergi.
How do I query a string from JSON based on another string within the JSON in PostgreSQL?
Suppose I have the following JSON, which is the result of parsing urls parameters from a log file.
{
"title": "History of Alphabet",
"author": [
{
"name": "Larry"
},
]
}
{
"title": "History of ABC",
}
{
"number_pages": "321",
"year": "1999",
}
{
"title": "History of XYZ",
"author": [
{
"name": "Steve",
"age": "63"
},
{
"nickname": "Bill",
"dob": "1955-03-29"
}
]
}
All the fields in top-level, "title", "author", "number_pages", "year" are optional. And so are the fields in the second level, inside "author", for example.
How should I make a schema for this JSON when loading it to BQ?
A related question:
For example, suppose there is another similar table, but the data is from different date, so it's possible to have different schema. Is it possible to query across these 2 tables?
How should I make a schema for this JSON when loading it to BQ?
The following schema should work. You may want to change some of the types (e.g. maybe you want the dob field to be a TIMESTAMP instead of a STRING), but the general structure should be similar. Since types are NULLABLE by default, all of these fields should handle not being present for a given row.
[
{
"name": "title",
"type": "STRING"
},
{
"name": "author",
"type": "RECORD",
"fields": [
{
"name": "name",
"type": "STRING"
},
{
"name": "age",
"type": "STRING"
},
{
"name": "nickname",
"type": "STRING"
},
{
"name": "dob",
"type": "STRING"
}
]
},
{
"name": "number_pages",
"type": "INTEGER"
},
{
"name": "year",
"type": "INTEGER"
}
]
A related question: For example, suppose there is another similar table, but the data is from different date, so it's possible to have different schema. Is it possible to query across these 2 tables?
It should be possible to union two tables with differing schemas without too much difficulty.
Here's a quick example of how it works over public data (kind of a silly example, since the tables contain zero fields in common, but shows the concept):
SELECT * FROM
(SELECT * FROM publicdata:samples.natality),
(SELECT * FROM publicdata:samples.shakespeare)
LIMIT 100;
Note that you need the SELECT * around each table or the query will complain about the differing schemas.
It could be that I've created my index wrong, but I have a lead index with variable field names that I need to search through. I created a sub object called fields that contains name and value. Sample:
[
{
"name": "first_name",
"value": "XXX"
},
{
"name": "last_name",
"value": "XXX"
},
{
"name": "email",
"value": "X0#yahoo.com"
},
{
"name": "address",
"value": "X Thomas RD Apt 1023"
},
{
"name": "city",
"value": "phoenix"
},
{
"name": "state",
"value": "AZ"
},
{
"name": "zip",
"value": "12345"
},
{
"name": "phone",
"value": "5554448888"
},
{
"name": "message",
"value": "recently had XXXX"
}
]
name field is not_analyzed, and value field is analyzed and not, as .exact and .search
I thought I could get the results I want from a query string query doing something like
+fields.name: first_name +fields.value.exact: XXX
But it doesn't quite work the way I thought. I figure its because I'm trying to use this as mysql instead of as nosql, and there is a fundamental brain shift I must have.
While the approach you are taking probably should work with enough effort, you are much better off having explicit field names for everything, eg:
{
"name.first_name" : "XXX",
"name.last_name" : "XXX",
etc...
}
Then your query_string looks like this:
name.first_name:XXX
If you are a new to elasticsearch, play around with things before you add your mappings. The dynamic defaults should kick in and things will work. You then add mappings to get fine grained control over the field behavior.