Spring Data JPA
MongoRepository
Custom Queries
Java Programming
Database Operations

MongoRepository findByThisAndThat custom Query with multiple parameters

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Spring Data MongoRepository supports both derived query methods and explicit @Query definitions for multiple parameters. The main decision is readability versus query complexity. Derived names are concise for simple predicates, while @Query is clearer when field mapping or operators become non-trivial.

Many low-level Q and A style snippets solve the immediate error but skip the engineering context that keeps code reliable over time. A durable solution combines correct syntax with predictable behavior under real inputs, explicit failure handling, and verification that future refactors do not regress the outcome.

When evaluating a fix, also consider maintenance reality: who will own this code in six months, what observability exists in production, and which assumptions are most likely to break first. Capturing intent with small regression tests and clear naming drastically reduces re-learning cost when incidents happen under time pressure.

Core Sections

1. Start with the smallest correct implementation

Use derived method names for straightforward equality filters. This keeps repository interfaces declarative and reduces duplication between method names and query strings.

java
1public interface OrderRepository extends MongoRepository<Order, String> {
2    List<Order> findByCustomerIdAndStatus(String customerId, String status);
3    Optional<Order> findByCustomerIdAndOrderNumber(String customerId, String orderNumber);
4}

This baseline should be intentionally simple. Keep naming precise, make assumptions visible, and avoid premature abstractions. Once the smallest version behaves correctly, you gain a trustworthy reference point for future optimization and architectural changes.

At this stage, add lightweight assertions or logging around critical state transitions. That evidence is invaluable when later optimizations accidentally change behavior, because you can quickly compare current output against the known-good baseline rather than guessing where divergence started.

2. Harden the implementation for real usage

Switch to @Query when you need explicit field names, projection, or compound operators. Positional parameters keep methods concise while still expressing intent clearly.

java
1public interface OrderRepository extends MongoRepository<Order, String> {
2    @Query(value = "{ 'customerId': ?0, 'total': { $gte: ?1 }, 'status': ?2 }")
3    List<Order> findActiveAboveTotal(String customerId, BigDecimal minTotal, String status);
4
5    @Query(value = "{ 'customerId': ?0, 'createdAt': { $gte: ?1, $lt: ?2 } }")
6    List<Order> findInDateRange(String customerId, Instant from, Instant to);
7}

Production hardening is where many bugs are prevented. Address resource management, thread or event-loop safety, edge cases, and consistent error paths. If this logic is part of a service boundary, include clear contracts for inputs, outputs, and failure semantics.

It also helps to separate pure transformation logic from side-effectful operations such as network calls, database writes, or UI mutation. That split makes unit tests faster and deterministic, while integration tests can focus on boundary behavior and failure recovery policies.

3. Verify behavior and performance

Back query correctness with integration tests against a real Mongo instance (often Testcontainers). Also add indexes aligned to your compound filters, or even well-written repository methods will degrade at scale. Query readability and index strategy should be designed together.

A practical verification loop is straightforward and effective: one happy-path test, one edge-case test, and one failure-path test. Then run with representative data volume or user interactions. If behavior changes after refactoring, keep the regression test so the same issue does not return later.

Performance validation should align with user impact. For APIs, inspect latency percentiles and error rate. For mobile features, monitor frame drops and main-thread stalls. For algorithms and libraries, track complexity growth and memory churn under scaled inputs. Metrics tied to real outcomes keep optimization decisions grounded.

Common Pitfalls

  • Creating very long derived method names that hide intent.
  • Using @Query field names that drift from domain model mapping.
  • Ignoring compound indexes for multi-parameter predicates.
  • Returning broad result sets when pagination is required.
  • Skipping integration tests and discovering query errors only in production.

Summary

Use derived methods for simple filters and @Query for complex predicates. Pair repository definitions with integration tests and index design to keep behavior correct and fast. Pair concise implementation with explicit validation, and you get code that is both understandable today and maintainable as requirements evolve.


Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.