Files
life-echo/api/.agents/skills/redis-development/rules/json-vs-hash.md
Sully 53e0065e3e refactor(api): TOML 配置 SSOT、统一错误契约、Auth/事务加固与可观测性 (#33)
配置 SSOT(TOML + .env)
统一错误契约
Auth 与事务边界
Redis / Celery 可靠性:业务 Redis(DB/0)与 Celery broker/backend(DB/1)显式拆分;连接池、sync client
可观测性(OpenTelemetry + LGTM)
2026-05-22 13:44:50 +08:00

3.6 KiB

title, impact, impactDescription, tags, description, alwaysApply
title impact impactDescription tags description alwaysApply
Choose JSON vs Hash vs String Appropriately MEDIUM Optimal data model for your use case json, hash, string, data-structures, documents Choose JSON vs Hash vs String Appropriately true

Choose JSON vs Hash vs String Appropriately

Redis offers three ways to store structured data: JSON, Hash, and serialized strings. Each has distinct trade-offs around atomic partial operations and indexability.

Feature JSON Hash String (serialized JSON)
Structure Nested objects and arrays Flat key-value pairs Any structure
Atomic partial reads Yes ($.field) Yes (HGET) No (must fetch entire value)
Atomic partial writes Yes (JSON.SET $.field) Yes (HSET) No (must rewrite entire value)
RQE indexing Yes Yes No
Geospatial indexing Yes Yes No
Memory efficiency Higher overhead More efficient Most compact
Field-level expiration No Yes (HEXPIRE) No

When to use each:

  • JSON: Nested structures with atomic partial updates and indexing needs
  • Hash: Flat objects with atomic field access, field-level expiration, or memory efficiency
  • String: Simple caching where you always read/write the entire object and don't need indexing

Correct: Use JSON for nested structures with atomic partial updates.

Python (redis-py):

# JSON supports nested structures and atomic deep updates
redis.json().set("user:1001", "$", {
    "name": "Alice",
    "preferences": {"theme": "dark", "notifications": True}
})

# Atomic update of nested field - no read-modify-write needed
redis.json().set("user:1001", "$.preferences.theme", "light")

Java (Jedis):

import redis.clients.jedis.UnifiedJedis;
import redis.clients.jedis.json.Path2;
import org.json.JSONObject;

try (UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379")) {
    JSONObject user = new JSONObject();
    user.put("name", "Alice");
    user.put("preferences", new JSONObject().put("theme", "dark"));

    jedis.jsonSet("user:1001", new Path2("$"), user);

    // Atomic update of nested field
    jedis.jsonSet("user:1001", new Path2("$.preferences.theme"), "light");
}

Correct: Use Hash for flat objects with atomic field access.

Python (redis-py):

# Hash is efficient for flat data with atomic field operations
redis.hset("session:abc", mapping={
    "user_id": "1001",
    "created_at": "2024-01-01",
    "ip": "192.168.1.1"
})

# Atomic field read and update
ip = redis.hget("session:abc", "ip")
redis.hset("session:abc", "ip", "10.0.0.1")

Correct: Use String for simple caching without partial updates.

Python (redis-py):

import json

# String is fine when you always read/write the entire object
# and don't need indexing or partial updates
config = {"feature_flags": {"dark_mode": True}, "version": "1.0"}
redis.set("config:app", json.dumps(config), ex=3600)

# Must fetch and parse entire object
config = json.loads(redis.get("config:app"))

Incorrect: Using String when you need atomic partial updates.

Python (redis-py):

import json

# BAD: Must fetch, parse, modify, serialize, and rewrite entire object
data = json.loads(redis.get("user:1001"))
data["preferences"]["theme"] = "light"  # Not atomic!
redis.set("user:1001", json.dumps(data))
# Another client could have modified the object between GET and SET

Reference: Data Type Comparison