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?
"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.
TL;DR
We generally recommend the following approach:
MongoTemplate
.Details
For your example this would look something like this:
Define an interface for your custom code:
Add an implementation for this class and follow the naming convention to make sure we can find the class.
Now let your base repository interface extend the custom one and the infrastructure will automatically use your custom implementation:
This way you essentially get the choice: everything that just easy to declare goes into
UserRepository
, everything that's better implemented manually goes intoCustomUserRepository
. The customization options are documented here.This answer may be a bit delayed, but I would recommend avoiding the whole repository route. You get very little implemented methods of any great practical value. In order to make it work you run into the Java configuration nonsense which you can spend days and weeks on without much help in the documentation.
Instead, go with the
MongoTemplate
route and create your own Data access layer which frees you from the configuration nightmares faced by Spring programmers.MongoTemplate
is really the savior for engineers who are comfortable architecting their own classes and interactions since there is lot of flexibility. The structure can be something like this:MongoClientFactory
class that will run at the application level and give you aMongoClient
object. You can implement this as a Singleton or using an Enum Singleton (this is thread safe)FWIW, regarding updates in a multi-threaded environment:
MongoTemplate
provides out-of-the-boxupdateFirst
,updateMulti
,findAndModify
,upsert
... methods which allow you to modify a document in a single operation. TheUpdate
object used by these methods also allows you to target only the relevant fields.MongoRepository
only gives you the basicfind
,insert
,save
,delete
operations, which work with POJOs containing all the fields. This forces you to either update the documents in several steps (find
the document to update, modify the relevant fields from the returned POJO, and thensave
it), or define your own update queries by hand using@Query
.In a multi-threaded environment, like e.g. a Java back-end with several REST endpoints, single-method updates are the way to go, in order to reduce the chances of two concurrent updates overwriting one another's changes.
Example: given a document like this:
{ _id: "ID1", field1: "a string", field2: 10.0 }
and two different threads concurrently updating it...With
MongoTemplate
it would look somewhat like this:and the final state for the document is always
{ _id: "ID1", field1: "another string", field2: 15.0 }
since each thread is accesing the DB only once and only the specified field is changed.Whereas the same case scenario with
MongoRepository
would look like this:and the final document being either
{ _id: "ID1", field1: "another string", field2: 10.0 }
or{ _id: "ID1", field1: "a string", field2: 15.0 }
depending on whichsave
operation hits the DB first.So I'd say that
MongoTemplate
is a better option, unless you have a very elaborated POJO model or need the custom queries capabilities ofMongoRepository
for some reason.