6. Key-Value and Document Database DesignIntroduction and ContextNoSQL databases are most effective when their data model is derived from the way an application uses data rather than from a universal, normalized representation of business entities. This principle is especially visible in key-value and document databases. Both store aggregates that can be retrieved efficiently, but they differ in expressive power, querying style, and modeling choices. A key-value database treats data as a value addressed by a unique key. The value may be opaque to the database or may be interpreted only through limited operations. A document database stores structured documents—usually JSON or a binary JSON representation—and can query, index, validate, and update fields within those documents. These systems are widely used for sessions, shopping carts, profiles, content platforms, catalogs, mobile synchronization, event-oriented applications, and high-throughput web services. The central design question is not simply, “What tables or collections exist?” It is: “Which requests must the system answer, at what scale, with what consistency, and with which update patterns?” A strong model aligns keys, document boundaries, collections, validation, indexes, and atomic operations with those access patterns. Learning ObjectivesAfter studying this chapter, students should be able to: 1. Distinguish key-value and document database models and select between them appropriately. 2. Design durable, well-distributed keys and meaningful document boundaries. 3. Model embedded and referenced data according to access patterns and lifecycle relationships. 4. Define validation rules, indexes, and atomic updates for reliable applications. 5. Evaluate consistency, performance, scalability, security, and operational trade-offs. 6. Apply these principles to web, mobile, content, session, and commerce systems. 7. Critically assess common modeling errors and propose improved designs. From Business Objects to Access PatternsIn a relational design, modeling often begins with entities, attributes, and relationships, followed by normalization. In a document-oriented design, the starting point is frequently a catalogue of application operations: retrieve a product page, display a user’s recent orders, add an item to a cart, refresh a session, publish an article, or show a mobile user’s offline changes. An access pattern specifies the data required, the frequency of the operation, acceptable latency, ordering requirements, and whether the operation must be atomic. For example, “retrieve a cart by user identifier and update one line item” suggests a single cart document keyed by user identifier. “List all published articles in a category ordered by publication time” suggests an index or a key design based on category and time. The same business information may therefore be represented differently in different applications. This approach does not eliminate conceptual modeling. Entities, ownership, cardinality, lifecycle, and business rules remain important. It changes the optimization target: data is organized to make important operations predictable and efficient while preserving correctness. Key-Value Databases: Simple Access, Strong Operational DisciplineA key-value store maps a unique key to a value. The basic operations are commonly put, get, replace, and delete. Some systems also provide expiration, conditional writes, counters, atomic compare-and-set operations, transactions, streams, or scripting. The value may be a serialized JSON document, a string, a number, a list, or a binary object. In the purest model, the database does not understand the internal structure of the value. Consequently, a key-value store is highly suitable when the application already knows the key and usually retrieves or replaces the complete value. Typical uses include: - session records addressed by session identifier;
- short-lived authentication or password-reset tokens;
- shopping carts addressed by customer or cart identifier;
- feature flags and configuration snapshots;
- idempotency records for preventing duplicate requests;
- counters, rate-limit state, and cache entries.
Key design is crucial. A key should be unique, stable, sufficiently selective, and compatible with the partitioning strategy of the database. Namespaces such as `session:<id>`, `cart:<customerId>`, and `token:<hash>` improve operational clarity. Keys should not contain sensitive information unnecessarily, and identifiers supplied by users should be validated before being incorporated into keys. A key-value store is a poor choice when users must perform unpredictable searches over many fields, when the database must enforce complex relationships, or when partial field-level querying is central to the application. Such requirements may be addressed by a document database or another specialized system. Document Databases and Aggregate DesignA document database stores records as self-contained documents. A document can contain scalar fields, nested objects, and arrays. For example: ```json { "_id": "order-7812", "customerId": "cust-204", "status": "paid", "createdAt": "2025-02-18T10:30:00Z", "items": [ {"productId": "p-17", "name": "Keyboard", "quantity": 2, "unitPrice": 45.00} ], "total": 90.00, "shippingAddress": { "city": "Pune", "country": "IN" } } ``` The document represents an aggregate: a group of data normally loaded, changed, and governed together. Embedded data is appropriate when it is owned by the parent, has a similar lifecycle, is bounded in size, and is usually read with the parent. The shipping address is often embedded because an order should preserve the address used at purchase time, even if the customer later changes a profile address. References are preferable when a related object is shared, independently updated, very large, unbounded, or frequently queried on its own. A product catalog should generally not duplicate the full product description into every order. Nevertheless, commerce systems often store a snapshot of product name and price in an order line because historical accuracy is more important than avoiding all duplication. This illustrates a key principle: duplication is acceptable when it supports a deliberate read model and is governed by an update policy. Embedding and Referencing DecisionsThe following questions support a sound decision: 1. Is the child meaningful outside the parent? 2. Is the number of children bounded? 3. Are parent and child read together? 4. Must they be updated atomically? 5. Will the child change independently? 6. Would embedding cause excessive document growth or duplication? Embedding reduces round trips and simplifies atomic updates, but it can produce large documents and repeated data. Referencing reduces duplication and supports independent access, but it may require multiple reads, application-side joins, or transactions. There is no universal rule that all repeated information must be normalized or that all related information must be embedded. Keys, Identifiers, and DistributionA key has both a logical role and a physical role. Logically, it identifies a business object. Physically, it may determine the partition on which the object is stored. Sequential keys can create write concentration in systems that partition by key range. Conversely, random identifiers distribute writes but may make chronological retrieval difficult. Common identifier choices include UUIDs, application-generated slugs, database-generated identifiers, and compound keys. A compound key can encode access dimensions, for example `tenant:category:timestamp:itemId`. However, embedding too much mutable business meaning in a key creates maintenance problems. A customer’s email address is a poor primary key if the address can change. For multi-tenant systems, tenant identity should normally be part of the key or an unavoidable query condition. This reduces accidental cross-tenant access and can support tenant-level partitioning. Key construction must be centralized in application code or a data-access layer so that services do not generate incompatible formats. Hot keys are another concern. A single heavily accessed key, such as one global counter or a celebrity’s profile, may become a bottleneck even when the overall database is distributed. Techniques include local caching, partitioned counters, time-bucketed records, or redesigning the operation so that reads and writes are spread across keys. Collections, Schemas, and ValidationA document collection groups documents of broadly similar purpose. A collection should represent a useful operational boundary, not merely an entity name copied from an object-oriented class model. Separate collections may be suitable for products, orders, articles, and users; a single polymorphic collection may be justified when several document types share access patterns and indexes. Although document databases are schema-flexible, production systems still require schemas. Flexibility means that the database may permit variation; it does not mean that variation is harmless. Uncontrolled fields, inconsistent types, and multiple spellings of the same attribute increase query complexity and undermine analytics. Validation can be implemented at several levels: - application or service validation for user-friendly error messages;
- database validation for a final integrity boundary;
- type validation for strings, numbers, arrays, and dates;
- enumerated-value validation for states such as `pending`, `paid`, and `cancelled`;
- conditional validation for rules dependent on document state.
A useful validation policy distinguishes required fields, optional fields, immutable fields, and fields whose values are derived. Monetary amounts should use a representation that avoids inappropriate floating-point error, such as integer minor units or a database-supported decimal type. Dates should use a consistent timezone and format. Validation must also address maximum array lengths, document size, permitted nesting, and protection against unexpected fields where security requires it. Schema evolution should be planned. New fields can often be introduced additively, while readers temporarily support both old and new forms. Large migrations may use backfill jobs, dual reads, dual writes, or version fields. A version marker such as `schemaVersion: 2` can make migration behavior explicit. Indexes as Access-Pattern StructuresAn index is not a general performance decoration; it is a structure designed for particular predicates, sort orders, and uniqueness constraints. Before creating an index, identify the query it serves, its expected selectivity, write cost, storage cost, and lifecycle. Useful index categories include: - single-field indexes for equality or range filtering;
- compound indexes for a filter followed by a sort or additional predicate;
- unique indexes for identifiers such as usernames or external order numbers;
- partial or sparse indexes for documents containing a particular field;
- text or search indexes for controlled textual search;
- geospatial indexes for location queries;
- TTL indexes for automatic expiration where supported.
A compound index should reflect the query shape. Equality fields commonly precede range or sort fields, although the best order depends on the database optimizer and workload. An index on `tenantId, status, createdAt` may support a query that selects one tenant, filters by status, and sorts recent records. It does not automatically make every query on `status` efficient. Indexes consume memory and add work to writes. An application with numerous overlapping indexes may read quickly but write slowly and cost more to operate. Query plans should be inspected with representative data, not inferred solely from small development datasets. Index design should also account for low-cardinality fields, because an index on a Boolean field may be less useful than expected. Atomicity, Concurrency, and UpdatesAtomicity means that an operation is indivisible from the perspective of concurrent observers. A single-document update is commonly atomic in document databases, making document boundaries important correctness boundaries. If stock quantity and reservation status must change together, placing them in one document may simplify consistency. Atomic update operators allow a service to modify selected fields without replacing an entire document. Typical operations include setting a field, incrementing a counter, adding to a set, appending to an array, removing an array element, and updating a timestamp. Conditional updates are especially valuable: ```text update inventory item where productId = P17 and available >= 2 set available = available - 2 ``` The service should verify whether the condition matched. Otherwise, a failed reservation may be incorrectly reported as successful. Optimistic concurrency uses a version field or an update timestamp. A client reads version 4 and writes only if the current version remains 4; a concurrent update causes a conflict rather than silently overwriting data. Idempotency keys protect against retries: a request identifier is stored with its result, so repeating the same request does not create a second payment or order. Transactions spanning multiple documents are useful when a business invariant cannot be maintained within one aggregate. They also introduce coordination, latency, and possible contention. A transaction should not compensate for an unclear document boundary or be used automatically for every operation. Eventual consistency and asynchronous workflows may be more appropriate for secondary projections, notifications, search indexes, and analytics. Modeling Common Application DomainsWeb and Mobile ApplicationsUser profiles can be stored as documents when profile attributes are read together, while activity feeds and notifications are commonly modeled as append-oriented records or time buckets. Mobile applications benefit from compact documents, stable identifiers, synchronization metadata, and conflict-resolution policies. Offline clients require explicit handling of deleted records, clocks, duplicate submissions, and conflicting edits. Content ManagementAn article document may include title, author identifier, publication status, tags, a content representation, and revision metadata. Large media files should normally be stored in object storage, with metadata and references in the document database. Published content may be denormalized into a read-optimized document or cached representation. Draft and published versions should not be confused: publication is a state transition that should be auditable and, where required, reversible. Sessions and Security TokensSession records are naturally key-value data. A session key may map to user identifier, authentication time, expiry, device information, and security version. Expiration should be enforced by both a database TTL mechanism, where available, and application checks. Tokens should be random, sufficiently protected, revocable when required, and never stored or logged in plain form unnecessarily. Session data should be minimized because it may contain sensitive information. CommerceA cart is often one document per customer or cart identifier, containing bounded line items and a last-modified timestamp. An order is an immutable or carefully controlled historical record. Inventory updates require conditional atomic operations or a carefully designed reservation workflow. Product catalogs may use documents with embedded variants, attributes, and media references, but unbounded reviews, click events, and stock movements should usually be separate collections or streams. Illustrative Case Study: A Multi-Channel Retail PlatformBackgroundThis illustrative case concerns Northstar Retail, a fictional retailer operating a web store, mobile application, and customer-service portal. The platform must support product browsing, carts, orders, promotions, and inventory across several warehouses. Situation and ProblemThe initial system stored a large customer document containing profile data, all historical orders, cart contents, and notification records. As customers became more active, documents grew continuously. Product pages were slow because product and inventory data were retrieved together, while checkout occasionally overwrote cart changes made by another device. Analysts also found inconsistent product prices in historical orders. AnalysisThe access patterns have different lifecycles. Profile data is updated occasionally; carts are frequently updated; orders are historical; inventory changes rapidly; and notifications are append-oriented. Combining them in one document creates contention, unbounded growth, and inappropriate atomicity. Historical order totals must not depend on current catalog prices. Approach and SolutionThe redesigned model uses: - a `customers` document for stable profile information;
- a key-value `cart:<customerId>` record containing bounded line items and a version;
- an `orders` collection with embedded item snapshots, prices, tax, shipping address, and status history;
- inventory documents partitioned by warehouse and product;
- a separate notification collection with a time-oriented index;
- product documents containing catalog attributes and references to media in object storage.
Cart updates use optimistic concurrency and atomic line-item operations. Checkout creates an idempotency record before processing payment. Inventory is reserved through conditional updates, and order lines preserve the product name and price at purchase time. Indexes support product category browsing, customer order history, and notification retrieval by customer and creation time. Validation prevents negative quantities, invalid order states, and missing monetary fields. OutcomeThe design reduces document growth and isolates high-contention operations. Customer-service queries can retrieve orders without loading profile or notification data. Product changes do not rewrite historical orders, and repeated checkout requests can be recognized safely. The platform still requires operational monitoring, reconciliation for failed workflows, and a clear policy for inventory reservation expiry. Learning PointsThe case demonstrates that document boundaries should follow lifecycle and consistency needs. Strategic duplication—in this case, order-line snapshots—is valuable when it protects historical meaning. Key-value records are effective for bounded, direct-access state, while document collections are more appropriate for queryable aggregates. Most importantly, indexes and atomic operations are consequences of access patterns, not afterthoughts. Risks, Limitations, and Common MistakesA frequent mistake is treating schema flexibility as permission to omit design. Inconsistent field names, types, and state values eventually affect every service and report. Another is embedding unbounded arrays such as all comments, transactions, or events in a single document. Such documents become slow to update and may exceed platform limits. Over-normalization causes excessive round trips and application-side joins; over-denormalization creates expensive synchronization problems. The correct balance depends on read frequency, update frequency, data ownership, and consistency requirements. Creating indexes for every conceivable query also increases write cost and operational complexity. Developers sometimes perform read-modify-write cycles when an atomic operator would be safer. They may also ignore update-result counts, allowing failed conditional writes to appear successful. Blind document replacement can remove fields written by another service. Finally, relying on eventual consistency without explaining its user-visible effects can produce confusing experiences, especially during checkout, account changes, or security operations. Governance, Security, and Professional ResponsibilityDatabase design carries governance obligations. Access must be limited by role and, in multi-tenant systems, by tenant boundary. Sensitive fields should be encrypted in transit and protected at rest according to organizational policy. Logs, indexes, backups, and replicas may expose personal data and must be included in retention and deletion procedures. Data minimization is preferable to storing unnecessary identity, location, or behavioral information. A deletion request may require coordinated removal or anonymization across primary documents, caches, search indexes, backups, and event stores, subject to legal retention duties. Audit records should distinguish who changed data, what changed, and when. Schema validation, migration review, query authorization, backup testing, and disaster-recovery exercises are professional controls rather than optional administrative tasks. Contemporary DevelopmentsModern document platforms increasingly provide managed scaling, change streams, global replication, serverless triggers, and integrated search or vector capabilities. These features can support event-driven projections, personalized content retrieval, and semantic search, but they do not remove the need for explicit ownership, consistency, and cost analysis. Automation can detect slow queries, recommend indexes, expire temporary state, and validate schema conformance. Machine-learning or AI services may enrich documents with classifications or embeddings. Such enrichment introduces concerns about provenance, model error, privacy, and reprocessing cost. AI-generated fields should be treated as derived data with versioning and a means of correction, not as unquestionable facts. Best-Practice Design MethodA disciplined design process is as follows: 1. Catalogue business operations and rank them by importance and volume. 2. Define consistency and latency requirements for each operation. 3. Identify aggregates, ownership, lifecycle, and boundedness. 4. Select key formats that support uniqueness, tenancy, and distribution. 5. Decide deliberately which data is embedded, referenced, duplicated, or externalized. 6. Specify validation rules and a schema-evolution strategy. 7. Design indexes from representative query shapes. 8. Implement atomic and conditional updates, idempotency, and concurrency control. 9. Test with realistic document sizes, skewed traffic, failures, and concurrent clients. 10. Monitor query latency, index usage, hot keys, storage growth, validation failures, and operational cost. Chapter SummaryKey-value databases provide efficient direct access to values addressed by stable keys and are particularly suitable for sessions, carts, tokens, counters, and other bounded state. Document databases store queryable aggregates containing nested objects and arrays. Their flexibility still requires deliberate schemas, validation, versioning, and governance. Effective design begins with access patterns and proceeds through key selection, document boundaries, embedding or referencing, index construction, and atomic update design. Embedding supports efficient joint reads and single-document consistency; referencing supports independent lifecycle and unbounded relationships. Conditional updates, optimistic concurrency, idempotency, and carefully scoped transactions protect correctness under concurrent activity. Applications in commerce, content, mobile, web, and security demonstrate that duplication can be beneficial when it preserves historical or read-optimized representations. Finally, security, privacy, observability, cost, and evolving platform capabilities must be considered alongside functional requirements. Key TermsKey-value store: A database that associates a unique key with an opaque or simply structured value. Document database: A database that stores and queries structured documents, commonly in JSON-like form. Aggregate: A group of data treated as a unit for retrieval, modification, and consistency. Access pattern: A defined application operation specifying how data is retrieved or changed. Embedding: Storing related data inside a parent document. Referencing: Storing an identifier that points to data held elsewhere. Denormalization: Deliberate duplication or restructuring of data to improve access efficiency. Partition key: A key component used to distribute records across storage or processing partitions. Hot key: A disproportionately popular key that can create a performance bottleneck. Collection: A logical group of related documents. Schema validation: Rules controlling document structure, types, and permitted values. Schema evolution: The controlled modification of a data structure over time. Index: An auxiliary structure that accelerates specified queries or enforces uniqueness. Compound index: An index built over multiple fields in a defined order. TTL: Time-to-live behavior that expires data after a specified period. Atomic update: An indivisible change that cannot be observed partially. Optimistic concurrency: Conflict control that permits an update only if an expected version remains current. Idempotency: The property that repeating an operation produces the same intended effect as performing it once. Eventual consistency: A model in which replicas may temporarily differ but converge over time. Change stream: An ordered or observable feed of data modifications used for reactive processing. Review QuestionsShort Answer Questions1. What distinguishes a key-value database from a document database? 2. Define an access pattern and explain why it matters in NoSQL modeling. 3. State two conditions that favor embedding related data. 4. What is the purpose of a TTL mechanism? 5. How does optimistic concurrency prevent lost updates? Long Answer Questions1. Explain how document boundaries influence atomicity, performance, and scalability. 2. Compare embedding and referencing, including suitable examples from commerce applications. 3. Discuss the principles of key design in a distributed multi-tenant application. 4. Explain how validation, indexes, and schema evolution contribute to reliable document databases. 5. Describe a complete modeling process for a content-management application. Analytical / Application Questions1. A mobile application stores every user notification in the user profile document. Analyze the risks and propose a revised design. 2. An inventory update reads available stock, subtracts one, and writes the result back. Explain the concurrency problem and design a safer operation. 3. Design key-value and document structures for a checkout workflow that must tolerate client retries, preserve historical prices, and handle temporary inventory shortages. 22. Multiple Choice Questions with AnswersQuestion 1Which application is most naturally suited to a key-value database? A. Searching articles by several optional fields B. Retrieving a session by a known session identifier C. Joining customers with independently queried orders D. Running geographic queries on store locations Correct Answer: B. Retrieving a session by a known session identifier Question 2Why is a historical product price commonly embedded in an order line? A. To ensure current catalog updates rewrite the order B. To avoid validating monetary values C. To preserve the price that applied when the order was placed D. To make product search unnecessary Correct Answer: C. To preserve the price that applied when the order was placed Question 3Which situation most strongly favors referencing rather than embedding? A. A bounded shipping address used only by one order B. A small preference object always loaded with a profile C. An unbounded collection of independently updated comments D. A fixed set of cart line items Correct Answer: C. An unbounded collection of independently updated comments Question 4What is the principal risk of a hot key? A. It prevents all schema validation B. It concentrates traffic on one partition or record C. It automatically deletes related documents D. It converts a document database into a relational database Correct Answer: B. It concentrates traffic on one partition or record Question 5A query filters by tenantId and status and sorts by createdAt. Which index is most directly aligned with this access pattern? A. createdAt only B. status only C. tenantId, status, createdAt D. A unique index on customer email Correct Answer: C. tenantId, status, createdAt Question 6What should an application do after a conditional inventory update matches zero records? A. Assume the reservation succeeded B. Retry indefinitely without checking state C. Treat the condition as unmet and handle the reservation failure D. Replace the entire inventory collection Correct Answer: C. Treat the condition as unmet and handle the reservation failure Question 7Which technique is specifically intended to prevent a retried checkout request from creating a duplicate order? A. Idempotency key B. Unbounded embedding C. A sparse text index D. Random document deletion Correct Answer: A. Idempotency key Question 8Why can a document database still require schema validation? A. Because documents cannot contain nested objects B. Because flexible structure eliminates the need for indexes C. Because inconsistent types and fields create reliability and query problems D. Because validation guarantees zero network latency Correct Answer: C. Because inconsistent types and fields create reliability and query problems Question 9Which design best separates high-contention inventory from historical order data? A. Store all inventory movements inside the customer profile B. Use inventory documents for current stock and order snapshots for historical facts C. Store only the current product price and reconstruct old orders D. Place all customers and products under one global key Correct Answer: B. Use inventory documents for current stock and order snapshots for historical facts Question 10What is a major trade-off of using a transaction across multiple documents? A. It removes the need for access-pattern analysis B. It can provide stronger coordination but may add latency and contention C. It guarantees that every query uses an index D. It prevents all forms of eventual consistency in the system Correct Answer: B. It can provide stronger coordination but may add latency and contention
|