Issue
I have an object stored in mongo which looks like below (this is how it is shown in RoboMongo, when I view the document):
{
"_id": ObjectId("5e579c8674f69d1c1451f3ae"),
...
"timestamp": NumberLong(1582800002779),
...
"_class": "regular"
}
The object I store is defined like this:
public class MyObjectModel {
@Id
@Field(value = ID_FIELD_NAME)
private String id;
@Field(value = TIMESTAMP_FIELD_NAME)
private Long timestamp;
...
}
My intension is to get the list of objects within the timeframe. This is how I create query with spring data mongo db:
public List<Criteria> generateAllCriteria() {
List<Criteria> criteriaList = new ArrayList<>();
Optional.ofNullable(searchCriteria.getFromTimestamp()).map(ts -> criteriaList.add(generateFromTimestampCriteria(ts)));
Optional.ofNullable(searchCriteria.getToTimestamp()).map(ts -> criteriaList.add(generateToTimestampCriteria(ts)));
return criteriaList;
}
private Criteria generateFromTimestampCriteria(Long fromTimestamp) {
Criteria critFromTimestamp = Criteria.where(TIMESTAMP_FIELD_NAME).gte(fromTimestamp);
log.debug("From Timestamp criteria {}", critFromTimestamp.getCriteriaObject().toJson());
return critFromTimestamp;
}
private Criteria generateToTimestampCriteria(Long toTimestamp) {
Criteria critToTimestamp = Criteria.where(TIMESTAMP_FIELD_NAME).lt(toTimestamp);
log.debug("To Timestamp criteria {}", critToTimestamp.getCriteriaObject().toJson());
return critToTimestamp;
}
...
List<Criteria> criteriaList = generateAllCriteria();
Criteria finalCriteria = new Criteria();
finalCriteria = finalCriteria.andOperator(criteriaList.toArray(new Criteria[criteriaList.size()]));
log.debug("Final criteria {}", finalCriteria);
Query query = new Query();
query.addCriteria(finalCriteria);
List<MyObjectModel> myObjects = mongoTemplate.find(query, MyObjectModel.class);
The queries when I display them they are the following:
From Timestamp criteria { "timestamp" : { "$gte" : { "$numberLong" : "1582714365857" } } }
To Timestamp criteria { "timestamp" : { "$lt" : { "$numberLong" : "1582887165858" } } }
And the final query criteria seems to be this:
o.s.data.mongodb.core.MongoTemplate - find using query: { "$and" : [{ "timestamp" : { "$gte" : { "$numberLong" : "1582714365857" } } }, { "timestamp" : { "$lt" : { "$numberLong" : "1582887165858" } } }] } fields: Document{{}} for class: class mypackage.model.MyObjectModel in collection: myObjectModel
From the first glance it seems OK, but when I run it against Mongo manually it does not return any records, which in my opinion means that it is somehow incorrect. Here is what exactly I run on Mongo:
db.getCollection('my-collection').find({ "$and" : [{ "timestamp" : { "$gte" : { "$numberLong" : "1582707873806" } } }, { "timestamp" : { "$lt" : { "$numberLong" : "1582887165858" } } }] })
And it obviously does not return any records. But when I modify the query and get rid of $numberLong:
db.getCollection('my-collection').find({ "$and" : [{ "timestamp" : { "$gte" : 1582707873806 } }, { "timestamp" : { "$lt" : 1582887165858 } }] })
it works like a charm.
Can someone enlighten me and explain what I am doing wrong? How should it be done in correct way? How to make spring data mongo to create proper query?
Needless to say that string and ints are working perfectly fine. It is only about LONGs.
Thank you in advance for help.
Solution
As I understand:
- from/to are the only parameters in query
- both can be null
and assuming your model is:
public class Regular {
@Id
private String id;
@Field
private Long timestamp;
}
Then possible solution (IMHO much shorter) is:
// exists(true) is a "hack" to return the elements in case both from/to are null
public List<Regular> find(Long from, Long to) {
var criteria = where("timestamp").exists(true);
if(from != null) {
criteria.gte(from);
}
if(to != null) {
criteria.lte(to);
}
return mongoTemplate.find(Query.query(criteria), Regular.class);
}
PS. I have checked it with Spring Boot 2.2.4 and Mongo 3.6.
PS2. Still you can handle the case when from/to are both null by extra if condition and then remove exists(true).
Answered By - Ziemowit Stolarczyk
Answer Checked By - Timothy Miller (JavaFixing Admin)