# `Redis.JSON`
[🔗](https://github.com/joshrotenberg/redis_ex/blob/v0.7.1/lib/redis/json.ex#L1)

High-level document API for RedisJSON.

Wraps the RedisJSON commands with an Elixir-friendly interface: maps in,
maps out, atom or list path syntax instead of JSONPath strings, and
automatic JSON encoding/decoding.

For raw command access, see `Redis.Commands.JSON`.

## Quick Start

    # Store a document
    {:ok, "OK"} = Redis.JSON.set(conn, "user:1", %{name: "Alice", age: 30})

    # Get it back as an Elixir map
    {:ok, %{"name" => "Alice", "age" => 30}} = Redis.JSON.get(conn, "user:1")

    # Get specific fields
    {:ok, %{"name" => "Alice"}} = Redis.JSON.get(conn, "user:1", fields: [:name])

    # Update a nested field
    {:ok, "OK"} = Redis.JSON.put(conn, "user:1", :status, "online")

    # Merge fields (like PATCH)
    {:ok, "OK"} = Redis.JSON.merge(conn, "user:1", %{status: "offline", last_seen: "2026-04-03"})

    # Atomic increment
    {:ok, 31} = Redis.JSON.incr(conn, "user:1", :age, 1)

    # Array operations
    {:ok, 3} = Redis.JSON.append(conn, "user:1", :tags, "admin")
    {:ok, "admin"} = Redis.JSON.pop(conn, "user:1", :tags)

## Path Syntax

Paths can be atoms, lists, or raw JSONPath strings:

  * `:name` -> `$.name`
  * `[:address, :city]` -> `$.address.city`
  * `"$.users[0].name"` -> passed through as-is

## Options

Most functions accept:

  * `:atom_keys` -- return map keys as atoms (default: `false`)

# `append`

Appends one or more values to an array.

    {:ok, 3} = Redis.JSON.append(conn, "user:1", :tags, "admin")
    {:ok, 5} = Redis.JSON.append(conn, "user:1", :tags, ["editor", "reviewer"])

# `del`

Deletes a document or a path within it.

    {:ok, 1} = Redis.JSON.del(conn, "user:1")
    {:ok, 1} = Redis.JSON.del(conn, "user:1", :temporary_field)

# `exists?`

Checks if a key exists as a JSON document.

    true = Redis.JSON.exists?(conn, "user:1")

# `get`

Gets a JSON document or specific fields.

    {:ok, %{"name" => "Alice", "age" => 30}} = Redis.JSON.get(conn, "user:1")
    {:ok, %{"name" => "Alice"}} = Redis.JSON.get(conn, "user:1", fields: [:name])

Returns the document as a decoded Elixir map. JSONPath array wrapping
is automatically unwrapped for root-level gets.

# `incr`

Atomically increments a number at a path.

    {:ok, 31} = Redis.JSON.incr(conn, "user:1", :age, 1)
    {:ok, 10.5} = Redis.JSON.incr(conn, "user:1", :score, 0.5)

# `length`

Returns the length of an array.

    {:ok, 3} = Redis.JSON.length(conn, "user:1", :tags)

# `merge`

Merges fields into a document (like HTTP PATCH).

    Redis.JSON.merge(conn, "user:1", %{status: "online", last_seen: "2026-04-03"})

# `mget`

Gets a field from multiple keys.

    {:ok, ["Alice", "Bob"]} = Redis.JSON.mget(conn, ["user:1", "user:2"], :name)

# `pop`

Pops the last element from an array.

    {:ok, "hiking"} = Redis.JSON.pop(conn, "user:1", :tags)

# `put`

Sets a value at a specific path.

    Redis.JSON.put(conn, "user:1", :status, "online")
    Redis.JSON.put(conn, "user:1", [:address, :city], "NYC")

# `set`

Stores a JSON document.

    Redis.JSON.set(conn, "user:1", %{name: "Alice", age: 30})
    Redis.JSON.set(conn, "user:1", %{name: "Alice"}, nx: true)  # only if new
    Redis.JSON.set(conn, "user:1", %{name: "Alice"}, xx: true)  # only if exists

# `toggle`

Toggles a boolean at a path.

    {:ok, false} = Redis.JSON.toggle(conn, "user:1", :active)

# `type`

Returns the JSON type at a path.

    {:ok, :object} = Redis.JSON.type(conn, "user:1")
    {:ok, :array} = Redis.JSON.type(conn, "user:1", :tags)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
