JSON in MySQL: Columns, Functions and Indexing

A
Author
04 Aug, 2026 1 min read 205 views

MySQL's JSON column type validates documents on insert and stores them in an efficient binary format. It's handy for flexible attributes alongside normal columns.

Storing and reading

CREATE TABLE products (
  id    BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  name  VARCHAR(200) NOT NULL,
  attrs JSON NOT NULL
);

INSERT INTO products (name, attrs)
VALUES ('Phone', '{"brand": "Acme", "storage_gb": 128, "colors": ["black", "blue"]}');

SELECT name,
       attrs->'$.brand'       AS brand_json,   -- "Acme" (JSON, with quotes)
       attrs->>'$.brand'      AS brand,        -- Acme (unquoted text)
       attrs->>'$.colors[0]'  AS first_color
FROM products;

Filtering

SELECT name FROM products WHERE attrs->>'$.brand' = 'Acme';
SELECT name FROM products WHERE JSON_CONTAINS(attrs->'$.colors', '"blue"');
SELECT name FROM products WHERE 'blue' MEMBER OF (attrs->'$.colors');
SELECT name FROM products WHERE CAST(attrs->>'$.storage_gb' AS UNSIGNED) >= 128;

Updating

UPDATE products SET attrs = JSON_SET(attrs, '$.storage_gb', 256) WHERE id = 1;
UPDATE products SET attrs = JSON_ARRAY_APPEND(attrs, '$.colors', 'green') WHERE id = 1;
UPDATE products SET attrs = JSON_REMOVE(attrs, '$.colors[0]') WHERE id = 1;

Indexing JSON fields

JSON columns can't be indexed directly. Index an extracted value instead:

-- Option 1: a generated column
ALTER TABLE products
  ADD COLUMN brand VARCHAR(100) AS (attrs->>'$.brand') VIRTUAL,
  ADD INDEX idx_products_brand (brand);

-- Option 2: a functional index
CREATE INDEX idx_products_storage ON products ((CAST(attrs->>'$.storage_gb' AS UNSIGNED)));

-- Option 3: multi-valued index for arrays (used by MEMBER OF / JSON_CONTAINS)
CREATE INDEX idx_products_colors ON products ((CAST(attrs->'$.colors' AS CHAR(30) ARRAY)));

Turning JSON into rows

SELECT p.name, c.color
FROM products p,
     JSON_TABLE(p.attrs, '$.colors[*]' COLUMNS (color VARCHAR(30) PATH '$')) AS c;

Use JSON for genuinely variable data. Fields you always query, join or constrain are better as regular columns.

Was this article helpful?

Comments

No comments yet. Have a question or a tip? Be the first to share it.

Leave a comment

Comments are reviewed before they appear.