Using JSON in Postgres
The jsonb
data type in PostgreSQL allows you to store JSON (JavaScript Object Notation) data in a binary format.
Key Features of jsonb
:
- Efficient Storage:
jsonb
is stored in a binary representation, making it more compact thanjson
. - Better Performance:
jsonb
allows indexing, making it faster for querying and retrieval. - Flexibility: It supports a variety of operations like indexing, full-text search, and partial updates.
- Order Independent: Key order is not preserved (unlike
json
), and duplicate keys are removed.
How to Use the jsonb
data type with tenant_id
in PostgreSQL
1. Creating a table with jsonb
and tenant_id
column
CREATE TABLE products (
id INT,
tenant_id UUID NOT NULL,
name TEXT NOT NULL,
details jsonb,
CONSTRAINT PK_products PRIMARY KEY(tenant_id,id)
);
In this example:
id
: An integer primary key.tenant_id
: AUUID
type column for tenant isolation.name
: ATEXT
field for product name.details
: Ajsonb
field that will store additional product details like specifications, availability, etc.
2. Inserting data into a jsonb
column with tenant_id
You can insert JSON data into the jsonb
column, along with a tenant_id
, using standard SQL INSERT
:
INSERT INTO products (id, tenant_id, name, details)
VALUES (1, '550e8400-e29b-41d4-a716-446655440000', 'Smartphone', '{"brand": "XYZ", "model": "A100", "price": 699.99}');
Here, the tenant_id
is a UUID that ties the data to a specific tenant.
3. Querying jsonb
data by tenant_id
Accessing specific keys for a specific tenant
You can access specific keys in the jsonb
column and filter by tenant_id
:
SELECT details->'brand' FROM products
WHERE tenant_id = '550e8400-e29b-41d4-a716-446655440000' AND name = 'Smartphone';
This will return the brand for a given tenant’s product.
Using the @>
operator for containment
The @>
operator checks if one JSON object contains another JSON object. It’s useful for filtering rows by specific keys/values for a tenant.
SELECT * FROM products
WHERE tenant_id = '550e8400-e29b-41d4-a716-446655440000'
AND details @> '{"brand": "XYZ"}';
This finds all products with brand "XYZ" for a specific tenant.
4. Updating jsonb
data for a tenant
You can use the jsonb_set
function to update specific parts of a JSON object for a given tenant.
UPDATE products
SET details = jsonb_set(details, '{description}', '"A fast and powerful smartphone with a great processor"'::jsonb)
WHERE tenant_id = '550e8400-e29b-41d4-a716-446655440000' AND name = 'Smartphone';
This updates the price for the product belonging to a specific tenant.
5. Deleting a key from a jsonb
object by tenant
You can remove keys from a jsonb
object for a specific tenant:
-- Remove a single key:
UPDATE products
SET details = details - 'price'
WHERE tenant_id = '550e8400-e29b-41d4-a716-446655440000' AND name = 'Smartphone';
-- Remove multiple keys:
UPDATE products
SET details = details #- '{price, model}'
WHERE tenant_id = '550e8400-e29b-41d4-a716-446655440000' AND name = 'Smartphone';
This will delete the keys from the JSON object for the specified tenant.
6. Indexing jsonb
data by tenant_id
for faster queries
You can create indexes on the jsonb
fields for better query performance, particularly for multi-tenant systems.
GIN Index (Generalized Inverted Index)
This index allows fast searches for keys and values within jsonb
fields for tenants:
CREATE INDEX idx_products_details ON products USING GIN (details);
You can now query efficiently using operators like @>
, and PostgreSQL will leverage this index.
7. Aggregating data from jsonb
by tenant
You can extract and aggregate data from jsonb
fields for each tenant.
SELECT tenant_id, details->>'brand', COUNT(*)
FROM products
GROUP BY tenant_id, details->>'brand';
This query counts the number of products per brand for each tenant.
8. Full-Text Search on jsonb
fields by tenant
You can perform full-text searches on jsonb
columns for specific tenants using to_tsvector()
.
SELECT * FROM products
WHERE tenant_id = '550e8400-e29b-41d4-a716-446655440000'
AND to_tsvector(details->>'description') @@ to_tsquery('fast & processor');
This will search for products with the words "fast" and "processor" in the description
key for a specific tenant.
Common jsonb
functions & operators with tenant ID:
>
: Accesses a key, returns JSON data.>>
: Accesses a key, returns text.@>
: Checks containment (whether a JSON object contains another).jsonb_set()
: Updates a value for a key in a JSON object.- ``: Deletes a key from a JSON object.
||
: Concatenates two JSON objects.jsonb_array_elements()
: Expands a JSON array to a set of rows.
Best Practices for jsonb
with Multi-Tenancy:
- Indexing: Use GIN or BTREE indexes for frequent lookups by
tenant_id
and specific keys. - Normalization: Use
jsonb
for semi-structured data. For structured data, use regular columns and normalize the schema. - Use UUID for
tenant_id
: Ensure thetenant_id
is a UUID to uniquely identify tenants, providing clear data isolation.