Search code examples
javaspringmongodbspring-dataspring-data-mongodb

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 started using the MongoRepository but struggled with complex queries to find examples or 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 didn't get the syntax right. Even after reading the MongoDB documentation (non-working example due to the 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 all the documentation it seems that mongoTemplate is far better documented than MongoRepository. I'm referring to the following documentation:

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

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


Solution

  • "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.