index with this operator class is:
<programlisting>
CREATE INDEX idxgin ON api USING GIN (jdoc);
</programlisting>
The non-default GIN operator class <literal>jsonb_path_ops</literal>
does not support the key-exists operators, but it does support
<literal>@></literal>, <literal>@?</literal> and <literal>@@</literal>.
An example of creating an index with this operator class is:
<programlisting>
CREATE INDEX idxginp ON api USING GIN (jdoc jsonb_path_ops);
</programlisting>
</para>
<para>
Consider the example of a table that stores JSON documents
retrieved from a third-party web service, with a documented schema
definition. A typical document is:
<programlisting>
{
"guid": "9c36adc1-7fb5-4d5b-83b4-90356a46061a",
"name": "Angela Barton",
"is_active": true,
"company": "Magnafone",
"address": "178 Howard Place, Gulf, Washington, 702",
"registered": "2009-11-07T08:53:22 +08:00",
"latitude": 19.793713,
"longitude": 86.513373,
"tags": [
"enim",
"aliquip",
"qui"
]
}
</programlisting>
We store these documents in a table named <structname>api</structname>,
in a <type>jsonb</type> column named <structfield>jdoc</structfield>.
If a GIN index is created on this column,
queries like the following can make use of the index:
<programlisting>
-- Find documents in which the key "company" has value "Magnafone"
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"company": "Magnafone"}';
</programlisting>
However, the index could not be used for queries like the
following, because though the operator <literal>?</literal> is indexable,
it is not applied directly to the indexed column <structfield>jdoc</structfield>:
<programlisting>
-- Find documents in which the key "tags" contains key or array element "qui"
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc -> 'tags' ? 'qui';
</programlisting>
Still, with appropriate use of expression indexes, the above
query can use an index. If querying for particular items within
the <literal>"tags"</literal> key is common, defining an index like this
may be worthwhile:
<programlisting>
CREATE INDEX idxgintags ON api USING GIN ((jdoc -> 'tags'));
</programlisting>
Now, the <literal>WHERE</literal> clause <literal>jdoc -> 'tags' ? 'qui'</literal>
will be recognized as an application of the indexable
operator <literal>?</literal> to the indexed
expression <literal>jdoc -> 'tags'</literal>.
(More information on expression indexes can be found in <xref
linkend="indexes-expressional"/>.)
</para>
<para>
Another approach to querying is to exploit containment, for example:
<programlisting>
-- Find documents in which the key "tags" contains array element "qui"
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"tags": ["qui"]}';
</programlisting>
A simple GIN index on the <structfield>jdoc</structfield> column can support this
query. But note that such an index will store copies of every key and
value in the <structfield>jdoc</structfield> column, whereas the expression index
of the previous example stores only data found under
the <literal>tags</literal> key. While the simple-index approach is far more
flexible (since it supports queries about any key), targeted expression
indexes are likely to be smaller and faster to search than a simple
index.
</para>
<para>
GIN indexes also support the <literal>@?</literal>
and <literal>@@</literal> operators, which
perform <type>jsonpath</type> matching. Examples are
<programlisting>
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @? '$.tags[*] ? (@ == "qui")';
</programlisting>
<programlisting>
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @@ '$.tags[*] == "qui"';
</programlisting>
For these operators, a GIN index extracts clauses of the form
<literal><replaceable>accessors_chain</replaceable>