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.
Related
I have a slight problem with return data from Mongo find() vs a findOneAndReplace().
First, to know I'm working on an API that queries Mongo and returns data in JSON format.
Problem I'm having is that if I do a findOneAndReplace() to update and return the modified document, much like so:
// javaDocument() is just a org.bson.Document
var modDoc = jobsCollection.findOneAndReplace( javaDocument({"_id": jobid}), javaDocument(jobData), foarOptions );
if(isDefined("modDoc")) {
sReturn.DATA = deserializeJSON(modDoc.toJSON());
}
the dates set in my document returns within subkeys named "$date", which I do not want:
It really should read:
"created_at": "2022-02-03T10:15:01.634Z"
Doing a simple jobsCollection.find() however, seems to return me the date appropriately, like so:
var data= [];
jobsCollection.find( javaDocument({}) ).into(data);
sReturn.DATA = data;
What am I missing here ? I could simple copy the "$date" key and fix the structure, but I don't always know where in the structure I'll have dates.... Is there a way I could have this properly returned with FindOneAndReplace() ? I'm thinking in might have something to do with the modDoc.toJSON() but haven't quite found my answer yet...
Thanks for your time. Cheers! Pat
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.
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.
In a publishing flow I need to insert a DBObject into a mongo db collection using Java.
I receive the object as a String, and this has been passed to me from a .NET application that used article.ToBsonDocument().ToJson() on a POCO.
On my side of the flow, in Java, I tried just using BasicDBObject doc = (BasicDBObject) JSON.parse(content); but I get a com.mongo.util.JSONParseException on a Date:
"CreationDate" : ISODate("2013-03-18T08:50:53Z")
I can change how the content is generated in C#, and I can change how to write to the DB in java, my only constraint is that it must be passed as a string between the two systems.
Any suggestions?
EDIT Thanks to the tip from #Jim Dagg below, some googling for ISODate and BsonDocument turned out this gem. Changing the c# code to use
article.ToBsonDocument().ToJson(new JsonWriterSettings{OutputMode = JsonOutputMode.Strict});
fixed it.
The ISODate constructor call is what's causing the issue. From an issue on the MongoDB JIRA:
The parser accepts these two date formats: seconds ->
"yyyy-MM-dd'T'HH:mm:ss'Z'" or seconds.milleseconds ->
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" Just add seconds to your $date value
and the aggregation command should work. Here's the JSON doc that I
had success with: { "aggregate" : "test", pipeline : [ {$match : {
date : { $date : "2012-05-01T12:30:00Z" } } } ] }
If you remove the ISODate constructor and simply render your date as (for example) "2013-03-18T08:50:53Z", you should be in business.
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);