I am trying to convert the following query:
{ "cd" : { "$lte" : ISODate("2013-06-30T09:12:29Z") , "$gte" : ISODate("2013-06-11T09:12:29Z")}}
To use with MongoTemplate and Query.
At the moment i am doing and approach like:
Query query = new Query();
query.addCriteria(Criteria.where("cd").lte(request.getTo()).gte(request.getFrom()));
mongoTemplate.find(query,MyDesiredEntity.class)
But the query above returns no results when the first one returns around 15 which it should(request.getTo and request.getFrom are java.util.Date).
Is there a way to achieve this with org.springframework.data.mongodb.core.query.Query
I got this to work by reversing the lte and gte calls. I wrote a test to show it working:
#Test
public void shouldBeAbleToQueryBetweenTwoDates() throws Exception {
// setup
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
MongoTemplate mongoTemplate = new MongoTemplate(new Mongo(), "TheDatabase");
DBCollection collection = mongoTemplate.getCollection("myObject");
// cleanup
collection.drop();
// date that should match
Date expectedDate = dateFormat.parse("2013-06-12T00:00:00Z");
collection.insert(new BasicDBObject("cd", expectedDate));
// date that should not match (it's last year)
collection.insert(new BasicDBObject("cd", dateFormat.parse("2012-06-12T00:00:00Z")));
// create and execute the query
final Date to = dateFormat.parse("2013-06-30T09:12:29Z");
final Date from = dateFormat.parse("2013-06-11T09:12:29Z");
Query query = new Query();
query.addCriteria(Criteria.where("cd").gte(from).lte(to));
// check it returned what we expected
List<MyObject> basicDBObjects = mongoTemplate.find(query, MyObject.class);
Assert.assertEquals(1, basicDBObjects.size());
Assert.assertEquals(expectedDate, basicDBObjects.get(0).cd);
}
Notes:
This is TestNG not JUnit
I'm using SimpleDateFormat just to make testing of dates easier and (maybe) more readable
The main thing to note is:
query.addCriteria(Criteria.where("cd").gte(from).lte(to));
Before I reversed the order of the lte and gte the query was returning nothing.
Related
I am a newbie to MongoDB and having a hard time querying documents with simple filtering. I would like to ask if what is the equivalent of CAST(datetime AS DATE) of mysql in MongoDB?
here's my code.
"inspection": {"hourbeg": "2020-11-23 10:12:20"}
Bson filters = Filters.and(new BasicDBObject("center.code", code),
new BasicDBObject("inspection.hourbeg", transactionDate));
Bson sorts = Sorts.descending("printedOn");
List<Document> vehicles = collection.find()
.sort(sorts)
.filter(filters)
.into(new ArrayList<Document>());
Im still trying to understand this Aggregate in MongoDB.
Never mind guys, I was able to solve my problem using this method. Might be useful for others as well.
String startDate = transactionDate.toString()+" 00:00:00";
String endDate = transactionDate.plusDays(1).toString()+" 00:00:00";
Bson gt = Filters.gt("inspection.hourbeg", startDate);
Bson lt = Filters.lt("inspection.hourbeg", endDate);
Bson andDate = Filters.and(gt, lt);
Bson filters = Filters.and(new BasicDBObject("center.code", code),
andDate);
Bson sorts = Sorts.descending("printedOn");
List<Document> vehicles = collection.find()
.sort(sorts)
.filter(filters)
.into(new ArrayList<Document>());
Statement: I am trying to get the documents from MongoDB collection (Emp) using java.
Condition: Where it matches with the DOB(Date of birth) of a person.
Problem: However, it never returns a record.
But it works perfectly for other fields such as EmpID or EmpName etc. The document of my collection looks like this,
{
"_id" : ObjectId("5d4d9059f0b31921a4916a0c"),
"EmpID" : "1001",
"EmpName" : "John",
"Sal" : 30000.0,
"DOB" : ISODate("1989-06-09T18:30:00.000+0000"),
"Age" : 31.0
}
Please find the following java code that I have tried,
BasicDBObject dbo = new BasicDBObject();
dbo.append("DOB", new BasicDBObject("$eq","1989-06-10T00:00:00.000"));
FindIterable<Document> doc = coll.find(dbo);
for (Document dox : doc)
{
System.out.println(dox.toJson());
}
Please help
For ISODate it's needed to pass the Date object in BasicDBObject, not String, also timezone must be provided:
dbo.append("DOB", new BasicDBObject("$eq",new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXX").parse("1989-06-10T00:00:00.000+0000")));
For Date Of Birth better to use $gte and $lt comparition operators together in order to take full range of single day, like that:
Date dayStart = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXX").parse("1989-06-10T00:00:00.000+0000");
Date dayEnd = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXX").parse("1989-06-11T00:00:00.000+0000");
BasicDBObject query = new BasicDBObject("Date", new BasicDBObject("$gt", dayStart).append("$lte", dayEnd));
Following code doesn't give the expected results, i've tried with multiple documents, those documents structured as follows.
_id: 5a7714d44c75220958e6aa01
imei:355227045347655
point: [3.143453333333333,80.10954]
heading: 0
speed:0
timestamp: 2018-02-04 19:42:36.000
point_distance: 525.25
Now i need to calculate sum of point_distance of every record match with given imei and time period. I've tried to achieve this with following code but returns nothing even if required data exists.
public Object findDistance(long imei, Date from, Date to) {
List aggregationOps = new ArrayList<>();
//operations
aggregationOps.add(match(Criteria.where("imei").is(imei)));
aggregationOps.add(match(Criteria.where("timestamp").gte(from)));
aggregationOps.add(match(Criteria.where("timestamp").lte(to)));
aggregationOps.add(group("imei").sum("point_distance").as("distance"));
aggregationOps.add(project("imei").and("distance").previousOperation());
AggregationOptions agOps = new AggregationOptions.Builder().allowDiskUse(true).cursor(new BasicDBObject()).build();
return (DistanceInfo) getMongoTemplate()
.aggregate(newAggregation(aggregationOps).withOptions(agOps), Location.class, DistanceInfo.class)
.getUniqueMappedResult();
}
Date > from and to are formatted as yyyy-MM-dd hh:mm:ss
DistanceInfo class
public class DistanceInfo {
long imei;
double distance;
}
I'm new to this mongodb stuff and no idea what did i do wrong, how can i correct this ? any help is much appreciated.
Try this. this should work
MatchOperation matchOperation = match(Criteria.where("imei").is(imei)
.and("timestamp").gte(from.getTime()).lte(to.getTime()));
GroupOperation groupOperation = group("imei").sum("point_distance").as("distance");
ProjectionOperation projectionOperation = project().andExpression("imei").as("imei")
.andExpression("distance").as("distance");
Aggregation aggregation = newAggregation(matchOperation, groupOperation, projectionOperation);
AggregationResults<DistanceInfo> results = mongoTemplate.aggregate(aggregation, "location", DistanceInfo.class);
return results.getMappedResults();
I already can execute the desired query on mongoshell, but i need to make the same query using Java and MongoOperations.
I have checked this question, which is very similar, but it only has one condition, as mine has two and uses the $gte and $lt operators. Here's the working mongo Query:
db.getCollection('example').update({"idVar": "desiredValued"}, { $pull: { "listaHoras": { $gte: ISODate("2016-11-06T05:50:00.000Z"), $lt: ISODate("2016-11-06T06:30:00.000Z")}}})
Sample doc:
"_id" : ObjectId("58221b4610a3c71f1894ce75"),
"idVar" : "56b11259272f5515b05d70bc",
"date" : ISODate("2016-11-06T03:00:00.000Z"),
"listaHoras" : [
ISODate("2016-11-06T05:40:00.000Z"),
ISODate("2016-11-06T06:30:00.000Z"),
ISODate("2016-11-06T06:40:00.000Z")
]
Where i'll have the ISODATE as a Date variable in Java, and the desiredValue as a String variable.
So far, i have i did the following, using the previously mentioned question as example:
BasicDBObject match = new BasicDBObject("idVar", desiredValue); // to match your document
BasicDBObject update = new BasicDBObject("listaHoras", new BasicDBObject("itemID", "1"));
coll.update(match, new BasicDBObject("$pull", update));
But, as you can see, this is NOT equivalent to the desired query. Since the match for the $pull is matching "itemID"with "1". I do not know, nor was i able to find how to properly use the $gte and $lt on the same query. Neither on how to use just one or both of them. I know it CAN be done as seen on the MongoOperatioons API which says:
"update - the update document that contains the updated object or $ operators to manipulate the existing object."
Anyone knows how it can be done? And if the Date type in Java matches the ISODATE on the Mongo?
I managed to find a solution. It is similar to what Veeram posted as a answer but it's slightly different. I simply removed his updateCriteria and used a BasicDBObject in it's place.
Here's how the full code looks:
Query findQuery = new Query();
Criteria findCriteria = Criteria.where("idVar").is(idVar);
findQuery.addCriteria(findCriteria);
Update update = new Update().pull("listaHoras", new BasicDBObject( "$gte", start).append("$lte", end));
mongoOps.updateMulti(findQuery, update, "CollectionName");
Where start and end are Date variables recieved by the method. Also important to note that Mongo uses the UTC as default timezone, so we must properly format the time in order for it to remove the desired values.
You can try something like below. This will remove the two items from the listaHoras array.
Query findQuery = new Query();
Criteria findCriteria =
Criteria.where("idVar").is("56b11259272f5515b05d70bc");
findQuery.addCriteria(findCriteria);
LocalDate startDt = LocalDate.of(2016, 11, 6);
LocalTime startTm = LocalTime.of(5, 40, 0);
LocalDate endDt = LocalDate.of(2016, 11, 6);
LocalTime endTm = LocalTime.of(6, 35, 0);
Date start = Date.from(LocalDateTime.of(startDt, startTm).toInstant(ZoneOffset.UTC));
Date end = Date.from(LocalDateTime.of(endDt, endTm).toInstant(ZoneOffset.UTC));
Query updateQuery = new Query();
Criteria updateCriteria =
Criteria.where(null).gte(start).lt(end);
updateQuery.addCriteria(updateCriteria);
mongoOperations.updateMulti(findQuery, update, "example");
I have a list of files in a GridFS that I am attempting to query by date. The sample document looks like the following:
{
"_id" : ObjectId("52e431d3e84f6fa18c53c808"),
"chunkSize" : NumberLong(262144),
"length" : NumberLong(13021),
"md5" : "0eb01f0d266f4bf4764d4ffc7e70a7ed",
"filename" : "120_1390686674383",
"contentType" : null,
"uploadDate" : ISODate("2014-01-25T21:51:15.049Z"),
"aliases" : null
}
I am attempting to get the "most recent" according to timestamp by doing the following:
DateTime dt = new DateTime(queryObj.getTime()); //org.joda.DateTime
BasicDBObject sort = new BasicDBObject();
sort.put("uploadDate", -1);
BasicDBObject query = new BasicDBObject();
query.put("uploadDate", new BasicDBObject("$gte", dt));
DBCursor cursor = fileStore.getFileList(query, sort);
If I simply sort the fileStore I get numerous records back and I can enumerate via the cursor. However, whenever I try to use $gte or $lte I get zero results.
Is there a missing step?
You're passing in a joda DateTime reference which the driver doesn't know how to do. If you check the logs, you'll probably find that it essentially calls a toString() on that and passes that in. Since a string is not a Date, the comparison fails. Try passing in just a java.util.Date (you can get one from the DateTime, iirc).