Recherche…


Introduction

JSON - Notation d'objet de script Java, Postgresql supporte le type de données JSON depuis la version 9.2. Il existe des fonctions et des opérateurs prédéfinis pour accéder aux données JSON. L'opérateur -> renvoie la clé de la colonne JSON. L'opérateur ->> renvoie la valeur de la colonne JSON.

Création d'une table JSON pure

Pour créer une table JSON pure, vous devez fournir un seul champ avec le type JSONB :

CREATE TABLE mytable (data JSONB NOT NULL);

Vous devez également créer un index de base:

CREATE INDEX mytable_idx ON mytable USING gin (data jsonb_path_ops);

À ce stade, vous pouvez insérer des données dans la table et les interroger efficacement.

Interrogation de documents JSON complexes

Prenant un document JSON complexe dans une table:

CREATE TABLE mytable (data JSONB NOT NULL);
CREATE INDEX mytable_idx ON mytable USING gin (data jsonb_path_ops);
INSERT INTO mytable VALUES($$
{
    "name": "Alice",
    "emails": [
        "[email protected]",
        "[email protected]"
    ],
    "events": [
        {
            "type": "birthday",
            "date": "1970-01-01"
        },
        {
            "type": "anniversary",
            "date": "2001-05-05"
        }
    ],
    "locations": {
        "home": {
            "city": "London",
            "country": "United Kingdom"
        },
        "work": {
            "city": "Edinburgh",
            "country": "United Kingdom"
        }
    }
}
$$);

Requête pour un élément de niveau supérieur:

SELECT data->>'name' FROM mytable WHERE data @> '{"name":"Alice"}';

Requête pour un élément simple dans un tableau:

SELECT data->>'name' FROM mytable WHERE data @> '{"emails":["[email protected]"]}';

Requête pour un objet dans un tableau:

SELECT data->>'name' FROM mytable WHERE data @> '{"events":[{"type":"anniversary"}]}';

Requête pour un objet imbriqué:

SELECT data->>'name' FROM mytable WHERE data @> '{"locations":{"home":{"city":"London"}}}';

Performance de @> par rapport à -> et ->>

Il est important de comprendre la différence de performance entre l'utilisation de @> , -> et ->> dans la partie WHERE de la requête. Bien que ces deux requêtes semblent être globalement équivalentes:

SELECT data FROM mytable WHERE data @> '{"name":"Alice"}';
SELECT data FROM mytable WHERE data->'name' = '"Alice"';
SELECT data FROM mytable WHERE data->>'name' = 'Alice';

la première instruction utilisera l'index créé ci-dessus alors que les deux dernières ne le seront pas, nécessitant une analyse complète de la table.

Il est toujours possible d’utiliser l’opérateur -> lors de l’obtention des données résultantes, de sorte que les requêtes suivantes utiliseront également l’index:

SELECT data->'locations'->'work' FROM mytable WHERE data @> '{"name":"Alice"}';
SELECT data->'locations'->'work'->>'city' FROM mytable WHERE data @> '{"name":"Alice"}';

Utilisation des opérateurs JSONb

Création d'une base de données et d'une table

DROP DATABASE IF EXISTS books_db;
CREATE DATABASE books_db WITH ENCODING='UTF8' TEMPLATE template0;

DROP TABLE IF EXISTS books;

CREATE TABLE books (
  id SERIAL PRIMARY KEY,
  client TEXT NOT NULL,
  data JSONb NOT NULL
);

Remplissage de la base de données

INSERT INTO books(client, data) values (
    'Joe', 
    '{ "title": "Siddhartha", "author": { "first_name": "Herman", "last_name": "Hesse" } }'
),(
    'Jenny', 
    '{ "title": "Dharma Bums", "author": { "first_name": "Jack", "last_name": "Kerouac" } }'
),(
    'Jenny', 
    '{ "title": "100 años de soledad", "author": { "first_name": "Gabo", "last_name": "Marquéz" } }'
);

Permet de tout voir à l'intérieur des livres de table:

SELECT * FROM books;

Sortie:

-> opérateur renvoie des valeurs en dehors des colonnes JSON

Sélection d'une colonne:

SELECT client, 
    data->'title' AS title
    FROM books;

Sortie:

entrer la description de l'image ici

Sélection de 2 colonnes:

SELECT client, 
   data->'title' AS title, data->'author' AS author
   FROM books;

Sortie:

entrer la description de l'image ici

-> vs ->>

L'opérateur -> renvoie le type JSON d'origine (qui peut être un objet), tandis que ->> renvoie le texte.

Retourne des objets NESTED

Vous pouvez utiliser le -> pour renvoyer un objet imbriqué et ainsi enchaîner les opérateurs:

SELECT client, 
   data->'author'->'last_name' AS author
   FROM books;

Sortie:

entrer la description de l'image ici

Filtration

Sélectionnez des lignes en fonction d'une valeur dans votre JSON:

 SELECT 
 client,
 data->'title' AS title
 FROM books
  WHERE data->'title' = '"Dharma Bums"';

Notez que WHERE utilise -> donc nous devons comparer à JSON '"Dharma Bums"'

Ou nous pourrions utiliser ->> et comparer à 'Dharma Bums'

Sortie:

entrer la description de l'image ici

Filtrage imbriqué

Recherchez des lignes en fonction de la valeur d'un objet JSON imbriqué:

SELECT 
 client,
 data->'title' AS title
 FROM books
  WHERE data->'author'->>'last_name' = 'Kerouac';

Sortie:

entrer la description de l'image ici

Un exemple du monde réel

CREATE TABLE events (
  name varchar(200),
  visitor_id varchar(200),
  properties json,
  browser json
);

Nous allons stocker les événements dans cette table, comme les pages vues. Chaque événement a des propriétés, qui peuvent être n'importe quoi (par exemple, la page en cours) et envoie également des informations sur le navigateur (comme le système d'exploitation, la résolution d'écran, etc.). Les deux sont totalement gratuits et pourraient changer avec le temps (car nous pensons à des choses supplémentaires à suivre).

INSERT INTO events (name, visitor_id, properties, browser) VALUES
(
  'pageview', '1',
  '{ "page": "/" }',
  '{ "name": "Chrome", "os": "Mac", "resolution": { "x": 1440, "y": 900 } }'
),(
  'pageview', '2',
  '{ "page": "/" }',
  '{ "name": "Firefox", "os": "Windows", "resolution": { "x": 1920, "y": 1200 } }'
),(
  'pageview', '1',
  '{ "page": "/account" }',
  '{ "name": "Chrome", "os": "Mac", "resolution": { "x": 1440, "y": 900 } }'
),(
  'purchase', '5',
  '{ "amount": 10 }',
  '{ "name": "Firefox", "os": "Windows", "resolution": { "x": 1024, "y": 768 } }'
),(
  'purchase', '15',
  '{ "amount": 200 }',
  '{ "name": "Firefox", "os": "Windows", "resolution": { "x": 1280, "y": 800 } }'
),(
  'purchase', '15',
  '{ "amount": 500 }',
  '{ "name": "Firefox", "os": "Windows", "resolution": { "x": 1280, "y": 800 } }'
);

Maintenant, permet de sélectionner tout:

SELECT * FROM events;

Sortie:

entrer la description de l'image ici

Opérateurs JSON + fonctions d'agrégation PostgreSQL

En utilisant les opérateurs JSON, combinés aux fonctions d'agrégation PostgreSQL traditionnelles, nous pouvons tirer ce que nous voulons. Vous avez la pleine puissance d'un SGBDR à votre disposition.

  • Permet de voir l'utilisation du navigateur:

      SELECT browser->>'name' AS browser, 
        count(browser)
        FROM events
        GROUP BY browser->>'name';
    

Sortie:

entrer la description de l'image ici

  • Total des revenus par visiteur:

      SELECT visitor_id, SUM(CAST(properties->>'amount' AS integer)) AS total
      FROM events
      WHERE CAST(properties->>'amount' AS integer) > 0
      GROUP BY visitor_id;
    

Sortie:

entrer la description de l'image ici

  • Résolution d'écran moyenne

      SELECT AVG(CAST(browser->'resolution'->>'x' AS integer)) AS width,
        AVG(CAST(browser->'resolution'->>'y' AS integer)) AS height
      FROM events;
    

Sortie:

entrer la description de l'image ici

Plus d'exemples et de documentation ici et ici .



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow