@Document, MongoRepository, custom queries — MongoDB persistence in Spring.
Published February 15, 2025
Spring Data MongoDB maps Java objects to MongoDB documents and generates repository methods from method names.
@Document("products")
@CompoundIndexes({
@CompoundIndex(def = "{'category': 1, 'status': 1, 'sortOrder': 1}")
})
public class Product {
@Id
private String id;
@Indexed(unique = true)
private String slug;
private String name;
private String category;
private BigDecimal price;
private ProductStatus status;
@CreatedDate
private Instant createdAt;
@LastModifiedDate
private Instant updatedAt;
@Version
private Long version; // optimistic locking
}
public interface ProductRepository extends MongoRepository<Product, String> {
// Spring Data generates the query from the method name
Optional<Product> findBySlug(String slug);
List<Product> findByCategoryAndStatus(String category, ProductStatus status);
boolean existsBySlug(String slug);
boolean existsBySlugAndIdNot(String slug, String id);
Page<Product> findByStatus(ProductStatus status, Pageable pageable);
// Custom query when method naming isn't expressive enough
@Query("{ 'price': { $gte: ?0, $lte: ?1 }, 'status': 'ACTIVE' }")
List<Product> findByPriceRange(BigDecimal min, BigDecimal max);
}
@Service
public class ProductSearchService {
private final MongoTemplate mongoTemplate;
public List<Product> search(String keyword) {
Query query = new Query(
new Criteria().orOperator(
Criteria.where("name").regex(keyword, "i"),
Criteria.where("description").regex(keyword, "i")
)
).with(Sort.by(Sort.Direction.DESC, "createdAt"));
return mongoTemplate.find(query, Product.class);
}
}
spring:
data:
mongodb:
uri: mongodb+srv://user:pass@cluster.mongodb.net/mydb?retryWrites=true
auto-index-creation: true # creates @Indexed annotations automatically
Know the difference between @Transient (field not persisted to MongoDB) and @Field("mongoFieldName") (map Java field to a different MongoDB field name).
Also explain optimistic locking: @Version Long version — when two threads read the same document and both try to save, the second save throws OptimisticLockingFailureException because the version has already changed.