Spring Data MongoDB Aggregation Match with Date and average - java

I'm using mongoDB java driver to query transactions between date range and average of value with aggregate framework. This is my mongo query (it works):
db.campaignsForChatUsers.aggregate([{$match:{'created' :
{$gte : ISODate('2017-09-30T11:35:35.155Z'), $lt : ISODate('2019-09-30T11:35:35.155Z')}}},
{$group: {_id : "_id", aveTime: { $avg : "$details.nostradamusOfferCalculatingTime"}}}])
The java code I'm using to make query:
public Double getAverageTimeWithPeriod(){
MongoCollection<Document> dbCollection = mongoTemplate.getCollection(ChatUserCampaign.COLLECTION_NAME);
Date fromDate = LocalDate.parse("2019-10-01").toDate();
Date toDate = LocalDate.parse("2020-03-13").toDate();
BasicDBObject match = new BasicDBObject("$match",
new BasicDBObject("created",
new BasicDBObject("$gte", fromDate/*getDate("01/10/2019")*/).append("$lt", toDate/*getDate("20/10/2019")*/)));
BasicDBObject group = new BasicDBObject("$group",
new BasicDBObject ("_id",
new BsonField("averageTime",
new BsonDocument("$avg,",
new BsonString("$details.nostradamusOfferCalculatingTime")))));
List<Bson> aggregators = null;
assert false;
aggregators.add(match);
aggregators.add(group);
AggregateIterable<Document> output = dbCollection.aggregate(aggregators);
//AggregationOutput output1 = dbCollection.aggregate(Arrays.asList(match,group));
Document result = output.first();
return result.getDouble("averageTime");
}
But this jaja query is returning empty results (in line with: aggregators.add(match); - I get NullPointerException).

Mongo don't understand 01/10/2019 format rather it understand ISO format. Hence, you must be using something like ISODate("2015-06-17T10:03:46Z") in place of fromDate and toDate. Date or LocalDate don't work.

Related

Convert data strings into Date format using ISODate function during the insertion mongo query to java code

db.collection.find().forEach(function(element){
element.BOOKING_CREATED_DATE = ISODate(element.BOOKING_CREATED_DATE);
db.collection.save(element);
})
Please help to convert this query to DBobject type to run in spring boot
Finally found the answer
MongoClient mongo = new MongoClient();
DB db = mongo.getDB("datarepo");
DBCollection collection = db.getCollection("rawdata");
db.eval("db.rawdata.find( { BOOKING_CREATED_DATE : { $type : 2 } } ).forEach(function(element){" +
"element.BOOKING_CREATED_DATE = ISODate(element.BOOKING_CREATED_DATE);" +
"db.rawdata.save(element);})")

Why is Mongo query and Java Mongo Driver query giving me very different results?

Why are these queries giving me very different results?
Mongo version:
db.journeydata.find({"$or" : [{"Start Date" : {'$gte' : ISODate("2015-07-01T00:00:00Z"), '$lte' : ISODate("2015-07-01T01:00:00Z")}},
{"End Date" : {'$gte' : ISODate("2015-07-01T00:00:00Z"), '$lte' : ISODate("2015-07-01T01:00:00Z")}}]}).count()
Java version:
BasicDBObject c1 = new BasicDBObject();
c1.put("Start Date", BasicDBObjectBuilder.start("$gte", fromDate).add("$lt", toDate).get());
BasicDBObject c2 = new BasicDBObject();
c2.put("End Date", BasicDBObjectBuilder.start("$gte", fromDate).add("$lt", toDate).get());
BasicDBList or = new BasicDBList();
or.add(c1);
or.add(c2);
DBObject query = new BasicDBObject("$or", or);
final DBCursor dbCursor = journeyColl.find(query);
final List<DBObject> journeyDBObject = dbCursor.toArray();
final List<Journey> journeyList = new ArrayList<Journey>(journeyDBObject.size());
for (int i = 0; i < journeyDBObject.size(); i++){
final DBObject dbObject = journeyDBObject.get(i);
final Journey journey = createJourney(dbObject);
journeyList.add(journey);
}
Where, fromDate and toDate are instances of Java.Util.Date. I have absolutely no idea why the queries are giving me different results. They should give me the same result. Any suggestions?
-- EDIT:
This is what mongo profiler gives me:
query:{
"$or" : [
{
"Start Date" : {
"$gte" : ISODate("2015-06-30T23:00:00Z"),
"$lt" : ISODate("2015-07-01T00:00:00Z")
}
},
{
"End Date" : {
"$gte" : ISODate("2015-06-30T23:00:00Z"),
"$lt" : ISODate("2015-07-01T00:00:00Z")
}
}
]
}
I have no idea why the dates changed? How can I avoid that?
-- EDIT:
This is how I generate the dates, I dont set any time zone:
final String begin = "2015-7-1T00:00:00.000Z";
final String end = "2015-7-31T00:00:00.000Z";
final DateTimeFormatter parser = ISODateTimeFormat.dateTime();
final DateTime beginDateTime = parser.parseDateTime(begin);
final DateTime endDateTime = parser.parseDateTime(end);
--- EDIT:
final DateTimeFormatter parser = ISODateTimeFormat.dateTime().withZone(DateTimeZone.UTC);
Setting timezone solved the issue.
Thanks.

How to Query MongoDB Using Child Nodes in Java

I'm trying to query mongodb with java. The name of my collection is: reads. Here is an example of a specific document I'm querying for:
{
"_id" : {
"d" : "B66929932",
"r" : "15500304",
"eT" : ISODate("2014-09-29T12:03:00Z")
},
"v" : 169000,
"iT" : ISODate("2015-04-10T20:42:07.577Z")
}
I'm trying to query where r = 15500304, eT = 2014-09-29T12:03:00Z and v = 169000. I'm able to do this in mongo pretty easily:
db.reads.find({ "_id.r" : "15500304", "_id.eT" : ISODate("2014-09-29T12:03:00Z"), "$where" : "this.v == 169000;"}).pretty()
I'm unable to figure out how to structure this in java. So far I've got:
DBCollection collection = db.getCollection("reads");
BasicDBObject andQuery = new BasicDBObject();
List<BasicDBObject> obj = new ArrayList<BasicDBObject>();
obj.add(new BasicDBObject("_id.r", "15500304"));
obj.add(new BasicDBObject("_id.eT", "2014-09-29T12:03:00Z"));
obj.add(new BasicDBObject("v", 169000));
andQuery.put("$and", obj);
DBCursor cursor = collection.find(andQuery);
while(cursor.hasNext()){
System.out.println(cursor.next());
}
My Question is: How do I query using these child nodes and return the matching document?
I'm unable to find any clear advice/examples online. Any and all advice is very appreciated.
You were close. Modify your query to:
DBCollection collection = db.getCollection("reads");
BasicDBObject query = new BasicDBObject();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
String dateInString = "2014-09-29T12:03:00Z";
Date date = df.parse(dateInString);
query.append("status.name", "Expired")
.append("_id.eT", date)
.append("v", 169000);
Or using QueryBuilder:
DBObject query = QueryBuilder.start()
.put("_id.r").is("15500304")
.put("_id.eT").is(date)
.put("v").is(169000)
.get();
DBCursor cursor = collection.find(query);
while(cursor.hasNext()){
System.out.println(cursor.next());
}

MongoDB date range query throws syntax errors when used in aggregation

I am using Java Driver for MongoDB to query database. I am getting syntax errors when trying to execute range query on a date field in aggregation. It works fine if I use it as part of find query only. Aggregation is the problem here. I used the following Java query code :
new BasicDBObject("requestDate", BasicDBObjectBuilder.start("$gte", fromDate).add("$lte", toDate).get());
requestDate is the field I want to query. I tried debugging the code and ran the generated query using command line and I still get syntax errors. Not sure whats wrong here.
Mongo Query generated by the code:
{ "requestDate" : { "$gte" : { "$date" : "2015-03-01T05:00:00.000Z"} , "$lte" : { "$date" : "2015-03-09T04:00:00.000Z"}}}
EDIT. Adding relevant Code:
BasicDBObject match = null;
if (organizationId != null) {
match = new BasicDBObject("$match", new BasicDBObject("organizationId", organizationId));
}
if (optionalParams != null) {
Date fromDate = (Date) optionalParams.get("fromDate");
Date toDate = (Date) optionalParams.get("toDate");
if (match == null) {
match = new BasicDBObject("requestDate", new BasicDBObject("$gte", fromDate).append("$lte", toDate));
} else {
match.append("requestDate", new BasicDBObject("$gte", fromDate).append("$lte", toDate));
}
}
DBObject project = new BasicDBObject("$project", MongoDBUtil.getProjectDateFields());
DBObject groupFields = new BasicDBObject("_id", MongoDBUtil.getGroupDateFields()).append("total", new BasicDBObject("$sum", 1));
DBObject group = new BasicDBObject("$group", groupFields);
DBObject sort = new BasicDBObject("$sort", new BasicDBObject("_id", 1));
List<DBObject> pipeline;
if (match != null) {
pipeline = Arrays.asList(match, project, group, sort);
} else {
pipeline = Arrays.asList(project, group, sort);
}
In brief, you broke your $match pipeline stage construction because like all pipeline directives that "key" is "mandatory. Your conditional building should not be checking is the existing state is null but rather "appending" to what you need to define at the top as a "empty" $match:
// BasicDBObject match = null; // wrong!
BasicDBObject match = new BasicDBObject("$match", new BasicDBObject()); // correct!
if (organizationId != null) {
match.append("organizationId", organizationId);
}
if (optionalParams != null) {
Date fromDate = (Date) optionalParams.get("fromDate");
Date toDate = (Date) optionalParams.get("toDate");
match.append("requestDate", new BasicDBObject("$gte", fromDate)
.append("$lte", toDate));
}
So then, without a value for organizationId you get a pipeline generated like so:
{ "$match": {
"requestDate" : {
"$gte" : { "$date" : "2015-03-01T05:00:00.000Z" },
"$lte" : { "$date" : "2015-03-09T04:00:00.000Z" }
}
}
Without that $match key this is not a valid pipeline stage and it will error on submission to the aggregation pipeline.
There is nothing wrong with the generated syntax and all, full explanation is in the manual under Extended JSON. The MongoShell uses "strict" mode as mentioned there so it requires it's own wrappers.

MongoDB Java Driver: Aggregation using $match with multiple condition

I've been doing some search but haven't been able to find the answer. From docs, In mongo, if
$match: { type: "airfare"}
translated as:
DBObject match = new BasicDBObject("$match", new BasicDBObject("type", "airfare") );
in Mongo Java driver, how to translate this one into Mongo java driver?
$match : { score : { $gt : 70, $lte : 90 } }
EDIT
This is what I actually wanted to do:
$match : { bookingDateTime: { $gte : fromDate, $lte : toDate } }
And this is how implemented in mongodb java driver, with no luck so far:
DBObject matchFields2 = new BasicDBObject("$match", new BasicDBObject("bookingDateTime", new BasicDBObject("$gte", fromDate.getTime()).append("$lte", toDate.getTime())));
DBObject match2 = new BasicDBObject("$match", matchFields2);
fromDate is a Calendar object so hence the getTime() method to convert Calendar class to Date class.
Object match = new BasicDBObject("$match",
new BasicDBObject("score",
new BasicDBObject("$gt", 70).append("$lte", 90) ) )

Categories

Resources