How to use "$match" and "$or" in mongo aggregation in java - java

I'm trying to load the matched documents into a temporary collection using aggregation query. Actually, I'm able to load all the matched documents into the temporary collection of MongoDB but my java program is throwing Null pointer exception at the for loop.
I'm totally stuck over here. May I know the reason for Null Pointer exception in this scenario . And can anyone please suggest me regarding the same ...
Document query = {"$or":[{"roll":1,"joiningDate":{"$gte":ISODate("2017-04-11T00:00:00Z")}},{"roll":2,"joiningDate":{"$gte": ISODate("2017-03-17T00:00:00Z")}}]};
Document match = new Document("$match",new Document("$or",query));
Document out =new Document("$out","TempCol");
System.out.println("Before Aggregation");
AggregateIterable<Document> resultAgg = collection.aggregate(Arrays.asList(match,out));
System.out.println("After aggregation");
for (Document doc : resultAgg){
System.out.println("The result of aggregation match:-");
}
System.out.println("Completed");

I generally prefer to keep the pipeline structured in one variable.
But the general idea here is use Document where you see {} and Arrays.asList where you see []:
List<Document> pipeline = Arrays.<Document>asList(
new Document("$match",
new Document("$or", Arrays.<Document>asList(
new Document("roll", 1)
.append("joiningDate", new Document(
"$gte", new DateTime(2017,04,11,0,0,0, DateTimeZone.UTC).toDate()
)),
new Document("controlId", 2)
.append("joiningDate", new Document(
"$gte", new DateTime(2017,03,17,0,0,0, DateTimeZone.UTC).toDate()
))
))
),
new Document("$out","TempCol")
);
AggregateIterable<Document> resultAgg = controlIssueCollection.aggregate(pipeline);
Also make sure when constructing a Date object with whatever your favorite construction method here is ( for me org.joda.time.DateTime ) that you are working with time in UTC, unless you really mean otherwise. And if you are comparing with values stored in MongoDB as shown in the shell, then you mean UTC.

Related

Remove multiple array Entries on Mongo using MongoOperations

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");

MongoDB: Query using $gte and $lte in java

I want to perform a query on a field that is greater than or equal to, AND less than or equal to(I'm using java btw). In other words. >= and <=. As I understand, mongoDB has $gte and $lte operators, but I can't find the proper syntax to use it. The field i'm accessing is a top-level field.
I have managed to get this to work:
FindIterable<Document> iterable = db.getCollection("1dag").find(new Document("timestamp", new Document("$gt", 1412204098)));
as well ass...
FindIterable<Document> iterable = db.getCollection("1dag").find(new Document("timestamp", new Document("$lt", 1412204098)));
But how do you combine these with each other?
Currently I'm playing around with a statement like this, but it does not work:
FindIterable<Document> iterable5 = db.getCollection("1dag").find(new Document( "timestamp", new Document("$gte", 1412204098).append("timestamp", new Document("$lte",1412204099))));
Any help?
Basically you require a range query like this:
db.getCollection("1dag").find({
"timestamp": {
"$gte": 1412204098,
"$lte": 1412204099
}
})
Since you need multiple query conditions for this range query, you can can specify a logical conjunction (AND) by appending conditions to the query document using the append() method:
FindIterable<Document> iterable = db.getCollection("1dag").find(
new Document("timestamp", new Document("$gte", 1412204098).append("$lte", 1412204099)));
The constructor new Document(key, value) only gets you a document with one key-value pair. But in this case you need to create a document with more than one. To do this, create an empty document, and then add pairs to it with .append(key, value).
Document timespan = new Document();
timespan.append("$gt", 1412204098);
timespan.append("$lt", 1412204998);
// timespan in JSON:
// { $gt: 1412204098, $lt: 1412204998}
Document condition = new Document("timestamp", timespan);
// condition in JSON:
// { timestamp: { $gt: 1412204098, $lt: 1412204998} }
FindIterable<Document> iterable = db.getCollection("1dag").find(condition);
Or if you really want to do it with a one-liner without temporary variables:
FindIterable<Document> iterable = db.getCollection("1dag").find(
new Document()
.append("timestamp", new Document()
.append("$gt",1412204098)
.append("$lt",1412204998)
)
);

MongoDB: Simple query issue

currently I'm trying to learn dealing with MongoDB in Java. I created the collection "plots" and inserted a document:
final Document plotObj = new Document();
plotObj.put(DataKey.PLOT_UUID.getKey(), plot.getUniqueId());
plotObj.put(DataKey.REGION_ID.getKey(), plot.getRegionId());
plotObj.put(DataKey.REGION_WORLD.getKey(), plot.getRegionWorld());
plotObj.put(DataKey.REGION_OWNER.getKey(), plot.getPlotOwner().isPresent() ? plot.getPlotOwner() : null);
plotObj.put(DataKey.PLOT_TRUSTED.getKey(), new BasicDBList().addAll(plot.getTrusted()));
this.collection.insertOne(plotObj);
"DataKey.PLOT_UUID.getKey()" represents a String. "plot.getUniqueId()" represents a java.util.UUID. After inserting this Document, I want to query it:
public boolean hasPlot(UUID plotId){
final BasicDBObject query = new BasicDBObject(DataKey.PLOT_UUID.getKey(), new BasicDBObject("$eq", plotId));
return this.collection.find(query).iterator().hasNext();
}
However this methods always returns false event though the Document was successfully inserted.
Maybe this problem can be fixed with ease but nevertheless: thanks in advance! :)
According to the documentation you don't need the $eq
just write
new BasicDBObject(DataKey.PLOT_UUID.getKey(), plotId));

$out in aggregation MongoDB

Can anyone explain me why in Java when i do an aggregation pipeline with "$out" don't write the result in the new collection when i write only this:
Document match = new Document("$match", new Document("top_speed",new Document("$gte",350)));
Document out=new Document("$out", "new_collection");
coll.aggregate(Arrays.asList(
match,out
)
);
When I save the aggregation result and I iterate on it, the new collection is created and the result of the match is inside (Java has an error obviously in this case):
AggregateIterable<Document> resultAgg=
coll.aggregate(Arrays.asList(
match,out
)
);
for (Document doc : resultAgg){
System.out.println("The result of aggregation match:-"+ doc.toJson());
}
I can't understand why.
You can call toCollection() method instead of iterating.
Document match = new Document("$match", new Document("top_speed", new Document("$gte", 350)));
Document out = new Document("$out", "new_collection");
coll.aggregate(Arrays.asList(match, out)).toCollection();

mongodb java driver hide id field in aggregation/projection operation

I'm performing an aggregation operation using the java mongodb driver, and I followed the example from the docs (pasted below). According to this, the _id field should be hidden. However, in my experience with my own code as well as the output of this example, the _id field doesn't hide even when setting the projection value to 0 (it works from the mongo shell). Does anyone know if this is a bug in the mongodb java driver? Or am I doing something incorrectly?
// create our pipeline operations, first with the $match
DBObject match = new BasicDBObject("$match", new BasicDBObject("type", "airfare") );
// build the $projection operation
DBObject fields = new BasicDBObject("department", 1);
fields.put("amount", 1);
fields.put("_id", 0);
DBObject project = new BasicDBObject("$project", fields );
// Now the $group operation
DBObject groupFields = new BasicDBObject( "_id", "$department");
groupFields.put("average", new BasicDBObject( "$avg", "$amount"));
DBObject group = new BasicDBObject("$group", groupFields);
// run aggregation
AggregationOutput output = collection.aggregate( match, project, group );
The _id field you are getting at the end is from the $group operator. If you want to rename it back to department, add another $project to the end of the pipeline and translate _id to department.

Categories