I have found a scenario where the query produced when using QueryDSL does not work with mongodb but it does work with jpa. The code is part of a project on github.
The method is in https://github.com/corneil/spring-data-demo/blob/master/src/main/java/org/springframework/data/demo/service/LocationAndDeviceServiceImpl.java
Code:
private List<LocationUpdate> findLocationsFunctions(String deviceId, Date startDate, Date endDate) {
logger.info("findLocations:" + deviceId + "," + startDate + "," + endDate);
DeviceInfo device = deviceInfoRepository.findByDeviceId(deviceId);
if (device == null) {
throw new DataRetrievalFailureException("DeviceInfo:" + deviceId);
}
return locationUpdateRepository.findByDeviceAndLocTimeBetween(device, startDate, endDate);
}
private List<LocationUpdate> findLocationsQsl(String deviceId, Date startDate, Date endDate) {
logger.info("findLocations:" + deviceId + "," + startDate + "," + endDate);
DeviceInfo device = deviceInfoRepository.findByDeviceId(deviceId);
if (device == null) {
throw new DataRetrievalFailureException("DeviceInfo:" + deviceId);
}
List<LocationUpdate> result = new ArrayList<LocationUpdate>();
Iterable<LocationUpdate> resultSet = locationUpdateRepository
.findAll(locationUpdate.device.eq(device).and(locationUpdate.locTime.between(startDate, endDate)));
for (LocationUpdate loc : resultSet) {
result.add(loc);
}
return result;
}
public List<LocationUpdate> findLocations(String deviceId, Date startDate, Date endDate) {
return findLocationsFunctions(deviceId, startDate, endDate);
// return findLocationsQsl(deviceId, startDate, endDate);
}
When commenting the findLocationsFunctions and uncommenting findLocationsQsl you will be able to induce the problem. The normal tests in the project will execute the JPA code using embedded H2. You will need access to mondodb to execute the tests for the mongo profile.. The database.properties file contains the mongodb url. Code:
./gradlew test testMongo
I think the problem lies in how the QueryDSL predicate is converted in Mongo Query. When I did the mongoTemplate initially . Code:
List<LocationUpdate> locations = mongoTemplate .find(
query(where("device").is(device).and("locTime").gte(startDate)
.and("locTime").lte(endTime)), LocationUpdate.class);
it gave an exception 'Due To Limitations Of The BasicDBObject, You Can’t Add A Second $And" and had to change to:
Code:
List<LocationUpdate> locations = mongoTemplate .find(
query(where("device").is(device).andOperator(
where("locTime").gte(startDate),
where("locTime").lte(endTime))), LocationUpdate.class);
I noticed that when using the finder method renders the following:
Code:
"locTime" : {
"$gt" : { "$date" : "2014-04-02T14:06:23.600Z"} ,
"$lt" : { "$date" : "2014-04-02T14:06:23.931Z"}
}
The code in findLocationsQsl doesn't render any criteria related to locTime.
Test with Spring Data MongoDB 1.5.0 and QueryDSL 3.3.4