Mongodb java springdata unable to get result for date equals query - java

I have inserted some test records to the mongo database with following structure.
{
"_id" : ObjectId("5563fe96a826638b48c77c26"),
"date" : ISODate("2015-05-02T07:00:00.326Z"),
"createdDate" : ISODate("2015-05-26T05:03:18.899Z"),
"updatedDate" : ISODate("2015-05-26T05:03:18.899Z"),
"status" : 0
}
Now when I try to query it using Spring data or via MongoDB I am always getting returned result list size to be 0.
Calendar calendar = Calendar.getInstance();
calendar.set(2015, 4, 2, 0, 0, 0);
Query query = new Query();
query.addCriteria(Criteria.where("date").is(calendar.getTime());
List<DateRecord> attendanceList = findAll(query, DateRecord.class);
System.out.println(attendanceList.size());
I am getting a very similar result for BasicDBObject, list of size 0.
DBCursor cursor;
BasicDBObject query1 = new BasicDBObject();
query1.append("date", calendar.getTime());
cursor = collection.find(query1);
System.out.println("Total objects returned "+cursor.size());
Any pointers on same will be highly appreciated. All I just want that data should be returned based upon year,month and day and any timestamp field values should be ignored.

I suggest using a different query - look for date greater than 2015-4-2 00:00:00 and explicitly less than 2015-4-3:00:00:00
Another approach, that I'm less enthusiastic about, would be to to add a field to the document just for the search purpose (e.g. "dateWithoutHour" calculated by java just before saving a document, and assuming data doesn't arrive from other sources). I don't like it, because I prefer my data to be pure logic and not change any time someone comes up with a new search requirement... but sometimes I had to resort to it).
And as always, when facing a difficult query it's tempting to consider $where , but I won't recommend it because it can't use indices.

Related

Java MongoDB numberLong query - Unable to fetch records

I wanted to fetch records between 1 date to other date from mongodb collection, where dates are stored as long in currenttimemillis. So I specified the query in java as
BasicDBObject query1 = new BasicDBObject();
long startGracePeriodInMillis = 1651676700254;
long endGracePeriodInMillis = 1653466067550;
query1.put("updated_at", new BasicDBObject("$gt", endGracePeriodInMillis).append("$lt", startGracePeriodInMillis));
this query1 is forming as
{"updated_at": {"$gt": {"$numberLong": "1653466067550"}, "$lt": {"$numberLong": "1651676700254"}}}
but im unable to fetch records, as the date is coming as string with $numberLong .. Im able to get records by mentioning only long without numberLong on server directly with
{"updated_at": {"$gt": 1653466067550, "$lt": 1651676700254}}
So what change should i need to make in
query1.put("updated_at", new BasicDBObject("$gt", endGracePeriodInMillis).append("$lt", startGracePeriodInMillis));
to form the query as
{"updated_at": {"$gt": 1653466067550, "$lt": 1651676700254}}
in the query it should come as only number like "$gt": 1653466067550 (which is giving results) but it is coming as "$gt": {"$numberLong": "1653466067550" - which is creating problem
You have start time and end time, you should search between them:
query1.put("updated_at", new BasicDBObject("$gt", startGracePeriodInMillis)
.append("$lt", endGracePeriodInMillis));
Not the other way around...
You are now searching for records that are after your end time or before your start time.
$gt means "greater than", you probably want to find documents with updated_at greater than your startGracePeriodInMillis...Same with $lt, meaning "less than", you probably want document with updated_at less than your endGracePeriodInMillis.

Spring Boot MongoRepository query via Date with Criteria lt & gte gives wrong result

When I query MongoRepository via Date field with Criteria in a Spring Boot application, the result is wrong. Here is my method:
Query query = new Query(new Criteria().andOperator(
Criteria.where("id").is(filter.getId()),
Criteria.where("datas.ts").lt(filter.getEndTime()).gte(filter.getStartTime())
));
List<PhaseData> phaseDatas = mongoOperations.find(query, PhaseData.class);
List<Data> result = new ArrayList<Data>();
for(Data pData : phaseDatas) {
result.addAll(pData.getDatas());
}
return result;
When I query with
{
"id" : "1234",
"startTime" : "2016-08-04 12:00",
"endTime" : "2016-08-04 15:00"
}
it gives me records with hour 16:54 & 21:12 too. How can I solve this issue?
Not sure if this addresses your question directly.
The DB won't return wrong result to the query. So I think it could be one of the following things:
It could be that the when you view the documents in mongodb, it displays date in iso format. So view the documents in the same format as you are creating dates for your query.
It could be timezone issue.
Mongodb dates can be considered as ISODate (MongoDB Date)
When you query, you create date objects in your timezone. So as a first debugging measure, I would see if both my DB and query timezones are the same.
Also, probably it would help if you query by creating date objects in ISODate by using SimpleDateFormat(SDF is not thread safe).
I have found that it could be confusing because the dates that you send are in a different format and the documents that you visually see in mongodb tool are displaying dates in iso format. I think that it could be the issue. The results are good, but probably you are viewing the two things differently and it causes the confusion.

Java & MongoDB query for date range

Before I start, I have already searched around for an answer to this issue and the best answer I could come up with is this question
I have one difference though. I have a table that maintains a history of many documents. Therefore I need to query on an ID as well as the date range. Here is what my query currently looks like in Java
BasicDBObject searchQuery = new BasicDBObject();
searchQuery.put("id", id);
searchQuery.put("dateModified", BasicDBObjectBuilder.start("$gte", fromDate).add("$lte", toDate).get());
DBCursor cursor = table.find(searchQuery);
This returns no results. The MongoQuery that is generated by this block of code looks like this:
db.history.find({ "id" : 12345 , "dateModified" : { "$gte" : { "$date" : "2015-01-19T00:00:00.000Z"} , "$lte" : { "$date" : "2015-01-25T00:00:00.000Z"}}});
When I manually type this into MongoDB command line, this also returns no results. I currently have one record in the database for testing purposes that looks like this:
{
"id" : NumberLong(12345),
"dateModified" : ISODate("2015-01-21T19:42:28.044Z")
}
This object should clearly match the query, yet nothing is returning, any ideas?
EDIT: So it turns out that the string generated by the query object doesn't match the ISODate object in the database. I'd like to clarify that fromDate and toDate are both java.util.Date objects. I'm still not sure how to solve this though.
I figured out the issue. I don't understand the cause, but the issue is with the BasicDBObjectBuilder not using the Date object correctly. I switched to QueryBuilder and built the exact same query and it returned results.
fromDate must be of the type Date not the String representation. An ISODate in the MongoDB storage Engine is not equal to the String representation of the same date and so they do not match.

MongoDB : How to make findAndModify returns the Last Updated Record

I am new to Mongo DB and having trouble as it is behaving differently in different environments ( Dev , QA and Production)
I am using findAndModify to Update the Records in my MongoDB .
There is a Job that runs daily which Updates /Inserts Data to Mongo DB , and i am using findAndModify to Update the Record .
But what i observed is that the first record that is returned by findAndModify is different in Dev , QA and Production environemnts although the three environments are having the same Data ??
As per the Mongo DB document , it states that findAndModify will modify the first document
Currently this is my code :
BasicDBObject update = new BasicDBObject();
update.append("$set", new BasicDBObject(dataformed));
coll.findAndModify(query, update);
Please let me know how can i make sure that , the findAndModify returns the Last Updated Record , rather than depending upon un predictable behaviour ??
Edited Part
I am trying to use sort for my code but it is giving me compilation errors
coll.findAndModify(query, sort: { rating: 1 }, update);
I have a field called as lastUpdated which is created using System.currentTimeMilis
So can i use this lastUpdated as shown this way to get the Last Updated Record
coll.findAndModify( query,
new BasicDBObject("sort", new BasicDBObject("lastUpdated ", -1)),
update);
It appears you are using Java, so you have to construct the sort parameter as a DBObject, just like the other parameters:
coll.findAndModify(
query,
new BasicDBObject("sort", new BasicDBObject("rating", 1)),
update);
As we already explained to you in your other question, you have to add a field to the document which contains the date it was changed and then sort by that field or you have to use a capped collection, because they guarantee that the insertion order is preserved.

Parameterized queries with Java and MongoDB

Can you do parameterized queries with Java and MongoDB - kind of like prepared statements with JDBC?
What I'd like to do is something like this. Set up a query that takes a date range - and then call it with different ranges. I understand that DBCursor.find(...) doesn't work this way - this is kind of pseudo-code to illustrate what I'm looking for.
DBCollection dbc = ...
DBObject pQuery = (DBObject) JSON.parse("{'date' : {'$gte' : ?}, 'date' : {'$lte' : ?}}");
DBCursor aprilResults = dbc.find(pQuery, "2012-04-01", "2012-04-30");
DBCursor mayResults = dbc.find(pQuery, "2012-05-01", "2012-05-31");
...
MongoDB itself doesn't support anything like this, but then again, it doesn't take too much sense as it needs to send the query over to the server every time anyway. You can simply
construct the object in your application yourself, and just modify specific parts by updating the correct array elements.
You should use Jongo, an API over mongo-java-driver.
Here is an example with parameterized query :
collection.insert("{'date' : #}", new Date(999));
Date before = new Date(0);
Date after = new Date(1000);
Iterable<Report> results = collection.find("{'date' : {$gte : #}, 'date' : {$lte : #}}", before, after).as(Report.class);

Categories

Resources