DEV Community

Cover image for How to Use JSONB in PostgreSQL with Step-by-Step Instructions
FOLASAYO SAMUEL OLAYEMI for TechPrane

Posted on • Edited on

How to Use JSONB in PostgreSQL with Step-by-Step Instructions

In this article, we'll explain how to use JSONB in PostgreSQL to store dynamic product attributes efficiently.

We'll cover why JSONB is useful, how to set up PostgreSQL, and perform full CRUD (Create, Read, Update, Delete) operations using Python and Flask. JSONB offers flexibility and performance, making it ideal for storing semi-structured data like product attributes, where schema can vary across records.

Check out this detailed example here! Perfect for hands-on learning and quick tips – don’t miss it!.

1. Setting Up the Database

To get started, we need to set up PostgreSQL and create a database that will store products with JSONB attributes.

Step 1: Install PostgreSQL

  • For Windows: Download and install PostgreSQL from the official website PostgreSQL Download. Follow the installation wizard to set up your database.
  • For Linux: Install via the terminal using:
  sudo apt-get update
  sudo apt-get install postgresql postgresql-contrib
Enter fullscreen mode Exit fullscreen mode

Step 2: Create a Database

Once PostgreSQL is installed, access the PostgreSQL command-line interface (psql):

psql -U postgres
Enter fullscreen mode Exit fullscreen mode

Create a new database for your project:

CREATE DATABASE products_db;
Enter fullscreen mode Exit fullscreen mode

Step 3: Create a Table to Store Products with JSONB Attributes

In your products_db database, create a table that stores product names and attributes as JSONB:

CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    attributes JSONB
);
Enter fullscreen mode Exit fullscreen mode

Here, the attributes column will store product details (e.g., size, color) in JSONB format, allowing for flexible attributes per product.

Step 4: Ensure Required Permissions

Make sure the PostgreSQL user has the necessary admin permissions to create tables and perform CRUD operations. Use this command to check roles:

\du
Enter fullscreen mode Exit fullscreen mode

To create a user with permissions:

CREATE USER your_username WITH PASSWORD 'your_password';
GRANT ALL PRIVILEGES ON DATABASE products_db TO your_username;
Enter fullscreen mode Exit fullscreen mode

2. Full CRUD Operations Using JSONB

Once the database is ready, we can move to performing CRUD operations (Create, Read, Update, Delete) using Python and Flask. We will connect to PostgreSQL using psycopg2.

Step 1: Install Required Python Libraries

You’ll need the following libraries for database connection and web development:

pip install psycopg2 flask
Enter fullscreen mode Exit fullscreen mode

Step 2: Establish a Database Connection in Python

Using the psycopg2 library, connect to your PostgreSQL database:

import psycopg2

def connect_db():
    conn = psycopg2.connect(
        host="localhost",
        database="products_db",
        user="your_username",
        password="your_password"
    )
    return conn
Enter fullscreen mode Exit fullscreen mode

Step 3: Creating a Product (Insert Operation)

Define an API endpoint in Flask to allow users to create a new product with attributes:

@app.route('/product', methods=['POST'])
def create_product():
    data = request.json
    name = data['name']
    attributes = data['attributes']

    conn = connect_db()
    cur = conn.cursor()
    cur.execute(
        "INSERT INTO products (name, attributes) VALUES (%s, %s) RETURNING id",
        (name, psycopg2.extras.Json(attributes))
    )
    product_id = cur.fetchone()[0]
    conn.commit()
    cur.close()
    conn.close()

    return jsonify({"id": product_id, "message": "Product created successfully!"}), 201
Enter fullscreen mode Exit fullscreen mode

Here, the attributes are stored in JSONB format, and the product is saved in the products table.

Step 4: Reading Products (Read Operation)

Create an endpoint to fetch all products along with their JSONB attributes:

@app.route('/products', methods=['GET'])
def get_products():
    conn = connect_db()
    cur = conn.cursor()
    cur.execute("SELECT id, name, attributes FROM products")
    products = cur.fetchall()
    cur.close()
    conn.close()

    return jsonify([{"id": p[0], "name": p[1], "attributes": p[2]} for p in products]), 200
Enter fullscreen mode Exit fullscreen mode

This endpoint retrieves the products and parses the JSONB attributes.

Step 5: Updating Product Attributes (Update Operation)

To update a product’s attributes, use this endpoint:

@app.route('/product/<int:product_id>', methods=['PUT'])
def update_product(product_id):
    data = request.json
    attributes = data['attributes']

    conn = connect_db()
    cur = conn.cursor()
    cur.execute(
        "UPDATE products SET attributes = %s WHERE id = %s",
        (psycopg2.extras.Json(attributes), product_id)
    )
    conn.commit()
    cur.close()
    conn.close()

    return jsonify({"message": "Product updated successfully!"}), 200
Enter fullscreen mode Exit fullscreen mode

This modifies the attributes stored in JSONB format.

Step 6: Deleting a Product (Delete Operation)

Finally, implement a delete operation for a product:

@app.route('/product/<int:product_id>', methods=['DELETE'])
def delete_product(product_id):
    conn = connect_db()
    cur = conn.cursor()
    cur.execute("DELETE FROM products WHERE id = %s", (product_id,))
    conn.commit()
    cur.close()
    conn.close()

    return jsonify({"message": "Product deleted successfully!"}), 200
Enter fullscreen mode Exit fullscreen mode

3. Best Practices for Using JSONB in PostgreSQL

Indexing JSONB Fields

  • Why Index?: JSONB fields should be indexed for efficient querying, especially when dealing with large datasets.
  • Use GIN Index: This type of index optimizes searches inside JSONB fields.
  CREATE INDEX idx_attributes ON products USING GIN (attributes);
Enter fullscreen mode Exit fullscreen mode

Optimizing JSONB Queries

  • Avoid Deeply Nested Data: Avoid storing deeply nested objects, which can degrade performance.
  • Use JSONB Operators: Take advantage of operators like @> to query specific keys efficiently.
  SELECT * FROM products WHERE attributes @> '{"color": "red"}';
Enter fullscreen mode Exit fullscreen mode

JSONB Anti-Patterns

  • Don’t Overuse JSONB: Use JSONB only for flexible attributes. For fixed schema data, prefer traditional SQL columns.
  • Don’t Store Large Blobs: Storing huge chunks of data in JSONB (e.g., files, images) can slow down queries.

Conclusion

With the steps provided, you can set up PostgreSQL with JSONB and implement full CRUD operations in Python. JSONB is highly flexible for storing dynamic data, and with the right optimizations, it can provide excellent performance.

To learn more, click on the link below to read further instructions on how to set up PostgreSQL for a seamless flow:

Learn More About PostgreSQL Setup

Thanks for reading...
Happy Coding!

Top comments (2)

Collapse
 
dailysandbox profile image
Art

I would only use jsonb columns for storing settings, or similar. It seems having normalized columns has a better performance overall.

Collapse
 
chris_levis_d1e25f4e33755 profile image
Chris Levis

good