Strong answer
Data design starts from queries and invariants: constraints in the database protect correctness, indexes are chosen from real WHERE, JOIN and ORDER BY patterns, and every schema change ships as a versioned, reviewable migration. Caching is an optimization layered on top of a correct source of truth, so define what may be stale, for how long, and how entries are invalidated. Pick a document store such as MongoDB only when the access pattern really is aggregate-shaped.
Java example
1-- V7__add_order_status_index.sql (Flyway)
2CREATE INDEX CONCURRENTLY idx_orders_customer_created
3 ON orders (customer_id, created_at DESC);
4
5@Service
6class ProductCatalog {
7 private final ProductRepository products;
8 ProductCatalog(ProductRepository products) { this.products = products; }
9
10 @Cacheable(cacheNames = "product", key = "#sku", unless = "#result == null")
11 public ProductView find(String sku) {
12 return products.findViewBySku(sku);
13 }
14
15 @CacheEvict(cacheNames = "product", key = "#sku")
16 public void priceChanged(String sku) { }
17}