Christopher Armstrong Christopher Armstrong - 1 year ago 576
Java Question

What's the difference between Spring Data's MongoTemplate and MongoRepository?

I need to write an application with which I can do complex queries using spring-data and mongodb. I have been starting by using the MongoRepository but struggled with complex queries to find examples or to actually understand the Syntax.

I'm talking about queries like this:

public interface UserRepositoryInterface extends MongoRepository<User, String> {
List<User> findByEmailOrLastName(String email, String lastName);

or the use of JSON based queries which I tried by trial and error because I don't get the syntax right. Even after reading the mongodb documentation (non-working example due to wrong syntax).

public interface UserRepositoryInterface extends MongoRepository<User, String> {
List<User> findByEmailOrFirstnameOrLastnameLike(String searchText);

After reading through all the documentation it seems that
is far better documented then
. I'm referring to following documentation:

Can you tell me what is more convenient and powerful to use?
? Are both same mature or does one of them lack more features then the other?

Answer Source

"Convenient" and "powerful to use" are contradicting goals to some degree. Repositories are by far more convenient that the templates but the latter of course give you more fine-grained control over what to execute.

As the repository programming model is available for multiple Spring Data modules you find more in-depth documentation of it in the general section of the Spring Data MongoDB reference docs.


We generally recommend the following approach:

  1. Start with the repository abstract and just declare simple queries using the query derivation mechanism or manually defined queries.
  2. For more complex queries, add manually implemented methods to the repository (as documented here). For the implementation use MongoTemplate.


For your example this would look something like this:

  1. Define an interface for your custom code:

    interface CustomUserRepository {
      List<User> yourCustomMethod();
  2. Add an implementation for this class and follow the naming convention to make sure we can find the class.

    class UserRepositoryImpl implements CustomUserRepository {
      private final MongoOperations operations;
      public UserRepositoryImpl(MongoOperations operations) {
        Assert.notNull(operations, "MongoOperations must not be null!");
        this.operations = operations;
      public List<User> yourCustomMethod() {
        // custom implementation here
  3. Now let your base repository interface extend the custom one and the infrastructure will automatically use your custom implementation:

    interface UserRepository extends CrudRepository<User, Long>, CustomUserRepository {

This way you essentially get the choice: everything that just easy to declare goes into UserRepository, everything that's better implemented manually goes into CustomUserRepository. The customization options are documented here.