How do you index an array inside a JSON with an Oracle 12c query? - sql

I have a table "move" with one column "move_doc" which is a CLOB. The json stored inside has the structure:
{
moveid : "123",
movedate : "xyz",
submoves: [
{
submoveid: "1",
...
},
{
submoveid : "2",
...
}
]
}
I know I can run an Oracle 12c query to access the submoves list with:
select move.move_doc.submoves from move move
How do I access particular submoves of the array? And the attributes inside a particular submove?

You have to use Oracle functions json_query and/or json_value like this:
SELECT json_value(move_doc, '$.submoves[0].submoveid' RETURNING NUMBER) FROM move;
returns 1.
SELECT json_query(move_doc, '$.submoves[1]') FROM move;
would return the second JSON element, i.e. something like
{
submoveid : "2",
...
}
json_value is used to retrieve a scalar value, json_query is used to retrieve JSON values. You might also want to have a look at json_table which returns an SQL result table and thus can be used in Joins.
See this Oracle Doc for more examples

Beda here from the Oracle JSON team.
We have added a new multi-value index in release 21c allowing you to index values from a JSON array. Obviously, 21c is brand new and you want to know how to do this in older releases: Functional indexes (using JSON_Value function) are limited to a single value per JSON document and therefore are not capable to index array values. But: there is a 'JSON search index' which indexes your entire JSON document and therefore also values in the array. Another solution is to use a materialized view usign JSON_Table. This will expand the array values into separate rows.Then you can add a regular B-Tree index on that column.
Sample code here:
JSON indexing with functional indexes and JSON search index
https://livesql.oracle.com/apex/livesql/file/content_HN507PELCEEJGVNW4Q61L34DS.html
JSON and materialized views
https://livesql.oracle.com/apex/livesql/file/content_HYMB1YBP4CPMG6T6MXY5G9X5L.html

From what I've looked, In Oracle, you can index the "whole array" as a single index entry, but not individual elements of an array.
NoSQL databases like MongoDB, Couchbase, Cassandra have "array/collection" indexes which can index individual elements or fields of objects within an array and query them.

Related

How to index name of an element in xml column in Postgres

I am trying to index name of elements and I keep running into this error
ERROR: set-returning functions are not allowed in index expressions
This is what I have tried so far.
Sample xml:
<book><title>Manual</title><chapter>1</chapter></book>
DDL:
CREATE INDEX test2_element_name_idx
ON test2 USING GIN(xpath('local-name(/*)',unnest(xpath('//book/*', xml_data))));
Is it possible to index on element names? At the end I want to index on all elements that are under <book> (i.e <title> <chapter>)
One of the sample usecase is, I wanna query (with xpath) to learn how many books have title. And I believe that indexing it would make the queries more efficient. Please correct me if I my understanding is incorrect.
A stated by a_horse_with_no_name, you can't use a function which returns multiple rows for indexing a table. What you can do instead is to build an array with the multiple rows returned by your function. I propose here after a solution that may need to be adjusted because I never used the xml data type and functions (json is better :-) :
CREATE OR REPLACE FUNCTION xml_data_agg(xml_data xml)
RETURNS xml[] LANGUAGE sql AS
$$
SELECT array(SELECT xpath('local-name(/*)',unnest(xpath('//book/*', xml_data)))) ;
$$ ;
CREATE INDEX test2_element_name_idx
ON test2 USING GIN(xml_data_agg(xml_data));
Then you can use this index in queries where you can put this type of where clause : WHERE xml_data_agg(xml_data) #> array[list_of_the_xlm_elements_to_be_searched]

Querying for all fields in a document

I want use gather all data within a database in RavenDB. Similar to SELECT * in SQL.
from #all_docs
select {
Name: Value
}
Instead of typing in all possible names and their corresponding values, I am wondering if there is an "all" character.
from #all_docs
should return all the documents

Search through jsonb column in ActiveRecord

My User model have jsonb column which names is raw. It looks like this:
{"client"=>{"tokens"=>["asdasd"]}}
Now I want to find a user by a token which is in raw["client"]["tokens"]. How can I do that?
I usually first craft such queries in a SQL console and then convert it to ActiveRecord.
You can navigate hash keys in Postgres. The query
SELECT
raw #> '{client,tokens}'
FROM users
will return just the tokens array from that path. Now we will need to check if it contains the value we are looking for. The query
SELECT
raw #> '{client,tokens}' ? 'asdasd'
FROM users
will select t for those row that have a matching token. Now you can move this to the WHERE section:
SELECT
*
FROM users
WHERE raw #> '{client,tokens}' ? 'asdasd'
And if this selects what you expect, then you can convert it to AR:
User.where("config #> '{client, tokens}' ? :token", token: 'asdasd')
Note that I can not use ? for parameter substitution and use :token instead. Also note that this only works in JSONB (Postgres 9.4+ https://www.postgresql.org/docs/9.4/static/functions-json.html#FUNCTIONS-JSONB-OP-TABLE)
Update:
You should(tm) (I have not tested this) get along with:
CREATE INDEX index_tokens ON users USING GIN ((raw #> '{client, tokens}'));
See https://www.postgresql.org/docs/9.6/static/datatype-json.html#JSON-INDEXING for more details
Update2:
Another way to query would be:
raw #> '{"client": {"tokens": ["asdasd"]}}'
Which should be able to use a simple GIN index on the raw column (which uses more space than the expression index described above).
CREATE INDEX index_user_raw ON users USING GIN (raw)
Again: details see the JSON INDEXING link above. And use a Query Visualizer to see the differences. I like http://tatiyants.com/pev

Extracting key/value pairs form JSON array

I have this JSON(B) column in my postgres database. I thrown in this column all the data that I get from an API. Now i need to extract some key/value pairs from this array.e.g. for a JSON array like:
[{"myKey1": "school type", "myKey2": "primary"}, {"myKey1": "study coverage", "myKey2": "secondary"}]
i need to extract:
myKey1: school type myKey2: primary
myKey1: study coverage myKey22: secondary
Since i am new to JSON, to me it appears that i first need to break the array into objects (surrounded by curly brackets) and than there are some postgres functions for objects (given in the following link https://www.postgresql.org/docs/9.4/static/functions-json.html) that i can use to extract the required key/value pairs.
My database table is:
CREATE TABLE "Education" (
"id" SERIAL NOT NULL,
"json_text" JSONB NOT NULL,
);
I am using the following query to achieve this:
SELECT tmp_col->>'myKey1'
FROM (
SELECT json_text->> 0 AS temp_col
FROM education
) AS temp_table
I get the following error when i run this query.
Any clues to what is missing?
Also is there any better ways to get the information in need. I am working in Java language to display the information.
Thanks.
If you can then please try to process JSON in java. You can query the complete JSON from postgres and then by using JSON API for Java you can then parse your JSON.

How do I query using fields inside the new PostgreSQL JSON datatype?

I am looking for some docs and/or examples for the new JSON functions in PostgreSQL 9.2.
Specifically, given a series of JSON records:
[
{name: "Toby", occupation: "Software Engineer"},
{name: "Zaphod", occupation: "Galactic President"}
]
How would I write the SQL to find a record by name?
In vanilla SQL:
SELECT * from json_data WHERE "name" = "Toby"
The official dev manual is quite sparse:
http://www.postgresql.org/docs/devel/static/datatype-json.html
http://www.postgresql.org/docs/devel/static/functions-json.html
Update I
I've put together a gist detailing what is currently possible with PostgreSQL 9.2.
Using some custom functions, it is possible to do things like:
SELECT id, json_string(data,'name') FROM things
WHERE json_string(data,'name') LIKE 'G%';
Update II
I've now moved my JSON functions into their own project:
PostSQL - a set of functions for transforming PostgreSQL and PL/v8 into a totally awesome JSON document store
Postgres 9.2
I quote Andrew Dunstan on the pgsql-hackers list:
At some stage there will possibly be some json-processing (as opposed
to json-producing) functions, but not in 9.2.
Doesn't prevent him from providing an example implementation in PLV8 that should solve your problem. (Link is dead now, see modern PLV8 instead.)
Postgres 9.3
Offers an arsenal of new functions and operators to add "json-processing".
The manual on new JSON functionality.
The Postgres Wiki on new features in pg 9.3.
The answer to the original question in Postgres 9.3:
SELECT *
FROM json_array_elements(
'[{"name": "Toby", "occupation": "Software Engineer"},
{"name": "Zaphod", "occupation": "Galactic President"} ]'
) AS elem
WHERE elem->>'name' = 'Toby';
Advanced example:
Query combinations with nested array of records in JSON datatype
For bigger tables you may want to add an expression index to increase performance:
Index for finding an element in a JSON array
Postgres 9.4
Adds jsonb (b for "binary", values are stored as native Postgres types) and yet more functionality for both types. In addition to expression indexes mentioned above, jsonb also supports GIN, btree and hash indexes, GIN being the most potent of these.
The manual on json and jsonb data types and functions.
The Postgres Wiki on JSONB in pg 9.4
The manual goes as far as suggesting:
In general, most applications should prefer to store JSON data as
jsonb, unless there are quite specialized needs, such as legacy
assumptions about ordering of object keys.
Bold emphasis mine.
Performance benefits from general improvements to GIN indexes.
Postgres 9.5
Complete jsonb functions and operators. Add more functions to manipulate jsonb in place and for display.
Major good news in the release notes of Postgres 9.5.
With Postgres 9.3+, just use the -> operator. For example,
SELECT data->'images'->'thumbnail'->'url' AS thumb FROM instagram;
see http://clarkdave.net/2013/06/what-can-you-do-with-postgresql-and-json/ for some nice examples and a tutorial.
With postgres 9.3 use -> for object access. 4 example
seed.rb
se = SmartElement.new
se.data =
{
params:
[
{
type: 1,
code: 1,
value: 2012,
description: 'year of producction'
},
{
type: 1,
code: 2,
value: 30,
description: 'length'
}
]
}
se.save
rails c
SELECT data->'params'->0 as data FROM smart_elements;
returns
data
----------------------------------------------------------------------
{"type":1,"code":1,"value":2012,"description":"year of producction"}
(1 row)
You can continue nesting
SELECT data->'params'->0->'type' as data FROM smart_elements;
return
data
------
1
(1 row)