Product Catalog
CRUD, Indexing, Embedded Documents, Caching
What Morphium Offers
Morphium maps Java objects to MongoDB documents with annotations. @Entity, @Id,
@Cache, @Index — four annotations turn a POJO into a cached, indexed document.
Embedded sub-documents, field name mapping and write safety are all declarative.
The Challenge
Traditional ODMs require XML mapping files or manual codec registries. The MongoDB Java driver gives you raw BSON documents with no type safety. Morphium eliminates both problems with a pure-annotation approach that works at the field level.
Morphium Features Used
Prerequisites & Key Concepts
- Lombok
@FieldNameConstantsgenerates an inner classProduct.Fieldswith constants likeFields.name,Fields.price. These are used in Morphium queries instead of hard-coded strings:query.f(Product.Fields.name). MorphiumIdis Morphium's own ObjectId type, compatible with MongoDB's native ObjectId. Import:de.caluga.morphium.driver.MorphiumId.@Embeddedgoes on the sub-document class (e.g.Category), NOT on the field in the parent. An@Embeddedclass must NOT also have@Entity.@Cacherequires the Morphium cache to be enabled. In Quarkus:quarkus.morphium.cache.read-cache-enabled=true(default). The cache is auto-invalidated on writes through the same Morphium instance.- Compound Index
@Indexon the class creates a compound index — optimal for price-range queries sorted by name.
Entity Relationship
Product (@Entity)
_id: MorphiumId @Id
name: String @Index
product_description: String @Property
price: double @Index
stock: int
category: Category @Embedded
tags: List<String>
@Embedded →
@Entity
@Embedded
@Reference
Entity Source Code
Product.java
Java
import de.caluga.morphium.annotations.Entity; import de.caluga.morphium.annotations.Id; import de.caluga.morphium.annotations.Index; import de.caluga.morphium.annotations.Property; import de.caluga.morphium.annotations.caching.Cache; import de.caluga.morphium.annotations.caching.Cache.ClearStrategy; import de.caluga.morphium.annotations.WriteSafety; import de.caluga.morphium.annotations.SafetyLevel; import de.caluga.morphium.annotations.DefaultReadPreference; import de.caluga.morphium.annotations.ReadPreferenceLevel; import de.caluga.morphium.driver.MorphiumId; import lombok.Data; import lombok.experimental.FieldNameConstants; import java.util.List; @Entity(collectionName = "products") 1 @Index("-price, name") 2 @Cache(maxEntries = 100, strategy = ClearStrategy.LRU, timeout = 30000) 3 @WriteSafety(level = SafetyLevel.NORMAL) 4 @DefaultReadPreference(ReadPreferenceLevel.PRIMARY) 5 @Data @FieldNameConstants public class Product { @Id 6 private MorphiumId id; @Index private String name; @Property(fieldName = "product_description") 7 private String description; @Index private double price; private int stock; private Category category; 8 private List<String> tags; }
1 Maps this class to the
products MongoDB collection2 Compound index on price (descending) and name — optimizes sorted range queries
3 LRU read cache: max 100 entries, auto-invalidated after 30s or on writes
4 Write concern: acknowledged writes (w:1)
5 Always read from the primary replica
6 Primary key → MongoDB
_id. Auto-generated on first store()7 Overrides the MongoDB field name: Java
description → MongoDB product_description8 Embedded sub-document — stored inline, no separate collection
Category.java
Java
import de.caluga.morphium.annotations.Embedded; import lombok.Data; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; @Embedded 1 @Data @NoArgsConstructor @AllArgsConstructor public class Category { private String name; private String description; }
1 Marks this class as an embedded sub-document — must NOT also have
@EntityService Code
CRUD Operations
Morphium API — CRUD
Java
import de.caluga.morphium.Morphium; @Inject Morphium morphium; // Store (insert or upsert) a product morphium.store(product); // Bulk insert morphium.storeList(products); // Delete a single entity morphium.delete(product); // Find by ID morphium.findById(Product.class, id);
Query Examples
Morphium API — Queries
Java
// Find all products morphium.createQueryFor(Product.class).asList(); // Search by name (regex, case-insensitive) morphium.createQueryFor(Product.class) .f(Product.Fields.name).matches("(?i)laptop") .asList(); // Price range query with sort morphium.createQueryFor(Product.class) .f(Product.Fields.price).gte(min) .f(Product.Fields.price).lte(max) .sort(Map.of(Product.Fields.price, 1)) .asList(); // Query embedded sub-document fields morphium.createQueryFor(Product.class) .f("category.name").eq("Electronics") .asList(); // Distinct values morphium.createQueryFor(Product.class) .distinct(Product.Fields.name);
Related Documentation
- Developer Guide — Object Mapping, @Entity, @Embedded
- Caching Examples — LRU Cache, Cache Invalidation
- API Reference — store(), Query, delete()
- Field Names — @Property, @FieldNameConstants