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

Christopher Armstrong picture Christopher Armstrong · Jun 9, 2013 · Viewed 69k times · Source

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:

@Repository
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).

@Repository
public interface UserRepositoryInterface extends MongoRepository<User, String> {
    @Query("'$or':[{'firstName':{'$regex':?0,'$options':'i'}},{'lastName':{'$regex':?0,'$options':'i'}}]")
    List<User> findByEmailOrFirstnameOrLastnameLike(String searchText);
} 

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

http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/

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

Answer

Oliver Drotbohm picture Oliver Drotbohm · Jun 9, 2013

"Convenient" and "powerful to use" are contradicting goals to some degree. Repositories are by far more convenient than 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'll find more in-depth documentation for it in the general section of the Spring Data MongoDB reference docs.

TL;DR

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.

Details

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;
    
      @Autowired
      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.