Что такое тип данных JSONB и каковы его ключевые отличия от JSON?

Ответ

JSONB — это бинарный формат для хранения JSON-данных в базах данных, в первую очередь в PostgreSQL. В отличие от текстового типа JSON, JSONB хранит данные в оптимизированном двоичном виде.

Ключевые особенности и преимущества JSONB:

  • Производительность: Запросы к данным в формате JSONB выполняются значительно быстрее, так как данные не требуют парсинга при каждом чтении. Однако вставка данных происходит немного медленнее из-за необходимости преобразования текста в бинарный формат.
  • Индексация: JSONB поддерживает полноценную индексацию (например, с помощью GIN-индексов), что позволяет эффективно искать значения внутри JSON-документов.
  • Эффективность: Удаляются незначащие пробелы и порядок ключей не сохраняется. Также JSONB сохраняет только последнее значение для дублирующихся ключей.

Сравнение JSON и JSONB

ХарактеристикаJSONJSONB
ХранениеКак есть, в текстовом видеОптимизированный бинарный формат
ПроизводительностьМедленнее при обработке и запросахБыстрее при обработке и запросах
Пробелы и порядокСохраняютсяНе сохраняются
ИндексацияОграниченнаяПолная поддержка (GIN, GIN(jsonb_path_ops))
ВставкаБыстрее (нет конвертации)Медленнее (требуется конвертация)

Пример работы с JSONB в Go (с pgx)

Для работы с JSONB в Go удобно использовать тип json.RawMessage, чтобы отложить парсинг данных до момента, когда это действительно необходимо.

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"
    "os"

    "github.com/jackc/pgx/v5"
)

// Структура для данных внутри JSON
type UserData struct {
    Username string   `json:"username"`
    Roles    []string `json:"roles"`
}

// Структура для строки из таблицы
type User struct {
    ID   int             `json:"id"`
    Data json.RawMessage `json:"data" // Поле для JSONB
}

func main() {
    // ... подключение к БД ...
    conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close(context.Background())

    var user User
    // Пример запроса к таблице users, где есть колонка data типа JSONB
    err = conn.QueryRow(context.Background(), "SELECT id, data FROM users WHERE id = $1", 1).Scan(&user.ID, &user.Data)
    if err != nil {
        log.Fatal(err)
    }

    // Теперь можно распарсить JSONB-данные в нужную структуру
    var userData UserData
    if err := json.Unmarshal(user.Data, &userData); err != nil {
        log.Fatal(err)
    }

    fmt.Printf("User ID: %d, Username: %s, Roles: %vn", user.ID, userData.Username, userData.Roles)
}