Redis / Basic: keys and bounded data structures / Lesson 3
Hashes, object models and key ownership
Represent bounded objects with Redis hashes while preserving identity, field serialization and lifecycle rules. Distinguish field updates from document-database validation.
On this page
Lesson goals
- Choose a hash boundary and interpret field-level operations.
- Define missing fields, partial updates and expiry ownership.
A hash groups named byte fields under one key
A Redis hash stores field/value pairs and can suit a bounded session summary or cached profile. It is not a nested JSON document with automatic schema validation or foreign keys. The application chooses field names, encoding and which fields are required. A single key makes related field updates convenient, but an enormous object with unbounded historical fields can still become expensive and contentious. Keep authoritative ownership separate from a cached representation and state whether fields form one coherent snapshot or may be updated independently.
Update a bounded object explicitly
Assume the training key is absent. HSET creates name and state fields and reports two newly added fields. HGET retrieves one value, while HMGET preserves the requested field order and includes a missing response for an absent field. Redis does not reinterpret the field name as an authorization rule. Use a key family whose owner guarantees hash type so a different component cannot accidentally place a string under the same identity. No command is executed here and the logical replies are derived from this declared fixture.
HSET lab:profile:7 name Lina state active
HGET lab:profile:7 name
HMGET lab:profile:7 state missingField
2
Lina
[active, missing]
Expected logical replies: 2 new fields, Lina, then [active, missing]. RESP/client presentation of a missing element varies.
A partial update does not remove old fields
HSET changes named fields and preserves other existing fields; HDEL removes specified fields. Reusing a hash key for a new schema version can therefore leave obsolete fields unless migration rules address them. Readers should distinguish an absent field from an empty byte string and malformed serialized content. HGETALL returns all fields and can be costly for large hashes, so select required fields when the response contract is narrow. Do not treat a count of newly added fields as a guarantee that every supplied fieldโs value changed.
Validate the application shape without connecting
This offline model checks required cached fields and rejects an unknown schema version. It deliberately operates on a local dictionary rather than pretending to implement Redis validation. A real writer must serialize fields consistently, and a real reader must define what happens when an old or incomplete cache entry is found. Falling back to the authoritative service can be safer than rendering a partially understood record, but fallback traffic must be bounded. Record how a schema migration invalidates or converts old cache values before deploying a reader that requires new fields.
def usable_profile(fields):
return fields.get('schema') == '1' and {'name', 'state'} <= fields.keys()
assert usable_profile({'schema': '1', 'name': 'Lina', 'state': 'active'})
assert not usable_profile({'schema': '2', 'name': 'Lina', 'state': 'active'})
assert not usable_profile({'schema': '1', 'name': 'Lina'})
The checks accept one complete version-1 record and reject the unknown or incomplete records. No server-side schema enforcement is claimed.
Choose key and field expiry intentionally
Key-level expiry removes the entire hash. Hash-field expiration is a newer capability introduced in Redis 7.4 and needs supported commands and client handling; it must not be assumed on every older or managed engine. A cache of a profile should not become the only authority for account status merely because HGET is fast. Define freshness and invalidation for revocation-sensitive fields, and inspect whether a partial field update preserves the intended key deadline. Grouping fields under one key reduces coordination work but does not create a relational integrity or durable recovery contract by itself.
Common errors and fixes
Old fields remain after a schema change
- Why it happens
- HSET was mistaken for whole-object replacement.
- How to fix it
- Apply a reviewed field migration or versioned-key invalidation policy.
- Prevent it next time
- Test mixed old/new fields and reader compatibility.
A missing field is treated as an empty valid value
- Why it happens
- Client decoding lost the presence distinction.
- How to fix it
- Preserve the missing response and handle incomplete records explicitly.
- Prevent it next time
- Include missing, empty and malformed field fixtures.
A hash unexpectedly expires as a whole
- Why it happens
- Key-level TTL was confused with individual field lifecycle.
- How to fix it
- Review the exact expiration contract and supported feature set.
- Prevent it next time
- Document whether expiry applies to the object or selected fields.
Check your understanding
1. A cached profile adds schema=2 but leaves an old privilege field. Why is a partial HSET insufficient migration evidence?
Show worked solution
HSET preserves unspecified fields, so the stored shape may combine incompatible versions. Define which fields version 2 permits, migrate or invalidate old entries, and verify readers do not interpret stale fields as current authority. A version label alone does not erase old data or prove all producers changed together.
2. Should a hash contain every lifetime audit event as a new field?
Show worked solution
Not without a justified bounded model. Unbounded fields increase transfer, memory and operation costs and can create a hot key. Store historical events in an appropriate durable event model, with a bounded cached summary if useful. Choose retention and recovery requirements before selecting a data structure merely because adding fields is convenient.
Key takeaways
- Hash field shape and schema ownership belong to the application.
- Partial updates, missing values and expiry need separate tests.