How to convert mongo shell query to java basicDBObject? - java

I am having following mongo query which is executed in mongo shell.
db.test.update({
uuid: "160597270101684",
sessionId: "160597270101684.1"
}, {
$setOnInsert: {
stamps: {
currentVisit: "1377500985",
lastVisit: "1377500985"
}
},
$push:{
visits: {
page: "google.com",
method: "GET"
}
}
}, { upsert:true })
Because i am new to java, I am little bit confused to create the basicDBObject.
I had tried like this for sample
BasicDBObject doc = new BasicDBObject("uuid",1).append("session",2);
BasicDBObject upsertion = new BasicDBObject("upsert",true);
collection.update(doc,upsertion);
But its not working.
Any help will be great.

The upsert option isn't specified with a DBObject but with a third argument to DBCollection.update
public WriteResult update(DBObject q, DBObject o, boolean upsert, boolean multi)
You'll need to form a DBObject for update by appending $setOnInsert, $push, stamps and visits.
BasicDBObject update = new BasicDBObject();
BasicDBObject stamps = new BasicDBObject();
stamps.append("currentVisit", "1377500985").append("lastVisit", "1377500985");
BasicDBObject visits = new BasicDBObject();
update.append("$setOnInsert", stamps).append("$push", visits);
collection.update(doc, update, true);

Related

Retrieve only the queried element in an object array in MongoDB using java

Suppose we have the following documents in a MongoDB collection:
{
"_id":ObjectId("562e7c594c12942f08fe4192"),
"shapes":[
{
"shape":"square",
"color":"blue"
},
{
"shape":"circle",
"color":"red"
}
]
},
{
"_id":ObjectId("562e7c594c12942f08fe4193"),
"shapes":[
{
"shape":"square",
"color":"black"
},
{
"shape":"circle",
"color":"green"
}
]
}
And the MongoDB query is
db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});
Can someone tell me how to write it in Java?
I am using:
List<BasicDBObject> obj = new ArrayList<>();
obj1.add(new BasicDBObject("shapes.color", "red"));
List<BasicDBObject> obj1 = new ArrayList<>();
obj2.add(new BasicDBObject("shapes.$", "1"));
BasicDBObject parameters1 = new BasicDBObject();
parameters1.put("$and", obj1);
DBCursor cursor = table.find(parameters1,obj2).limit(500);
and I am not getting anything.
The syntax of the Mongo Shell find function is:
db.collection.find(query, projection)
query document Optional. Specifies selection filter using query operators. To return all documents in a collection, omit this parameter or pass an empty document ({}).
projection document Optional. Specifies the fields to return in the documents that match the query filter.
When translating this for execution by the Mongo Java driver you need to construct separate BasicDBObject instances for;
the query
the projection
Here's an example:
MongoCollection<Document> table = ...;
// {"shapes.color": "red"}
BasicDBObject query = new BasicDBObject("shapes.color", "red");
// {_id: 0, 'shapes.$': 1}
BasicDBObject projection = new BasicDBObject("shapes.$", "1").append("_id", 0);
FindIterable<Document> documents = table
// assign the query
.find(query)
// assign the projection
.projection(projection);
System.out.println(documents.first().toJson());
Given the sample documents included in your question the above code will print out:
{
"shapes": [
{
"shape": "circle",
"color": "red"
}
]
}
This is identical to the output from db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});.

Update document in MongoDB with Java

I'm using MongoDB 3.2 and MongoDB Java Driver 3.2. I want to update the value the document having its ID. In order to do that I tried to use the following two approaches (found in Stackoverflow and MongoDB Blog):
Approach #1:
for(String docID : expiredDocsIDs) {
Bson filter = Filters.eq("_id", docID);
Bson updates = Updates.set("isExpired", true);
dbCollection.findOneAndUpdate(filter, updates);
}
Approach #2:
expiredDocsIDs.stream()
.forEach(docID -> {
BasicDBObject searchQuery = new BasicDBObject("_id", docID);
BasicDBObject updateFields = new BasicDBObject();
updateFields.append("isExpired", true);
updateFields.append("fetchStatus", "FETCHED");
BasicDBObject setQuery = new BasicDBObject();
setQuery.append("$set", updateFields);
dbCollection.updateOne(searchQuery, setQuery);
});
None of these approaches does not work.
It iterates over the list of documents IDs, executes the code but at the end of the code, when I check the documents in DB there is no any change in the documents' field I tried to update.
How can I update the specific document in MongoDB?
As BlakesSeven correctly noted, the problem was with a casting of _id field. The original code sent this parameter as String while the correct way is to send a parameter of ObjectId type.
The correct and worked code form MongoDB 3.2:
this.trackedEpisodesReg.entrySet().stream()
.filter(ep -> ep.getValue().isExpired())
.forEach(ep -> {
BasicDBObject updateFields = new BasicDBObject();
updateFields.append("isExpired", true);
BasicDBObject setQuery = new BasicDBObject();
setQuery.append("$set", updateFields);
BasicDBObject searchQuery = new BasicDBObject("_id", new ObjectId(ep.getValue().getEpisodeID()));
dbCollection.updateOne(searchQuery, setQuery);
});

How do I implement this MongoDB aggregation in Java

I have the following working MongoDB aggregation shell command:
db.followrequests.aggregate([{
$match: {
_id: ObjectId("551e78c6de5150da91c78ab9")
}
}, {
$unwind: "$requests"
}, {
$group: {
_id: "$_id",
count: {
$sum: 1
}
}
}]);
Which returns:
{ "_id" : ObjectId("551e78c6de5150da91c78ab9"), "count" : 7 }
I need to implement this in Java, I am trying the following:
List<DBObject> aggregationInput = new ArrayList<DBObject>();
BasicDBObject match = new BasicDBObject();
match.put("$match", new BasicDBObject().put("_id",new ObjectId(clientId)));
aggregationInput.add(match);
BasicDBObject unwind = new BasicDBObject();
unwind.put("$unwind", "$requests");
aggregationInput.add(unwind);
BasicDBObject groupVal = new BasicDBObject();
groupVal.put("_id", "$_id");
groupVal.put("count", new BasicDBObject().put("$sum", 1));
BasicDBObject group = new BasicDBObject();
group.put("$group", groupVal);
aggregationInput.add(group);
AggregationOutput output = followRequestsCol.aggregate(aggregationInput);
for (DBObject result : output.results()) {
System.out.println(result);
}
I am getting an exception:
mongodb the match filter must be an expression in an object.
Can you please help me identify the error in the above code. Thanks!
Try to print the value of aggregationInput and you will realise that .put() does not return a BasicDBObject but just the previous value associated to the key you update. Therefore, when you do:
match.put("$match", new BasicDBObject().put("_id",new ObjectId(clientId)));
You are actually setting $match to null, as new BasicDBObject().put("_id",new ObjectId(clientId)) returns null.
Update you code to something like:
List <DBObject> aggregationInput = new ArrayList <DBObject> ();
BasicDBObject match = new BasicDBObject();
BasicDBObject matchQuery = new BasicDBObject();
matchQuery.put("_id", new ObjectId());
match.put("$match", matchQuery);
aggregationInput.add(match);
BasicDBObject unwind = new BasicDBObject();
unwind.put("$unwind", "$requests");
aggregationInput.add(unwind);
BasicDBObject groupVal = new BasicDBObject();
groupVal.put("_id", "$_id");
groupVal.put("count", new BasicDBObject().put("$sum", 1));
BasicDBObject group = new BasicDBObject();
group.put("$group", groupVal);
aggregationInput.add(group);
AggregationOutput output = followRequestsCol.aggregate(aggregationInput);
for (DBObject result : output.results()) {
System.out.println(result);
}
Or, slightly more readable, use the fluent BasicDBObjectBuilder:
final DBObject match = BasicDBObjectBuilder.start()
.push("$match")
.add("_id", new ObjectId())
.get();
aggregationInput.add(match);
And it should work fine.
Each {} must be new DBObject. Use also .append(key,value) method to make more elegant.
Try this:
List<DBObject> pipeline = new ArrayList<DBObject>(Arrays.asList(
new BasicDBObject("$match", new BasicDBObject("_id",
new ObjectId("551e78c6de5150da91c78ab9"))),
new BasicDBObject("$unwind", "$requests"),
new BasicDBObject("$group",
new BasicDBObject("_id","$_id").append("count", new BasicDBObject("$sum", 1)))));
AggregationOutput output = followRequestsCol.aggregate(pipeline);
for (DBObject result : output.results()) {
System.out.println(result);
}
This is the final working version, based on the above suggestions
// Use mongodb aggregation framework to determine the count of followers
Integer returnCount = 0;
List aggregationInput = new ArrayList();
BasicDBObject match = new BasicDBObject();
BasicDBObject matchQuery = new BasicDBObject();
matchQuery.put("_id", new ObjectId(clientId));
match.put("$match", matchQuery);
aggregationInput.add(match);
BasicDBObject unwind = new BasicDBObject();
unwind.put("$unwind", "$requests");
aggregationInput.add(unwind);
BasicDBObject groupVal = new BasicDBObject();
groupVal.put("_id", null);
BasicDBObject sum = new BasicDBObject();
sum.put("$sum", 1);
groupVal.put("count", sum);
BasicDBObject group = new BasicDBObject();
group.put("$group", groupVal);
aggregationInput.add(group);
AggregationOutput output = followRequestsCol.aggregate(aggregationInput);
for (DBObject result : output.results()) {
returnCount = (Integer) result.get("count");
break;
}
return returnCount;

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 $in with $and Query

Is this type of query possible?
I need to query the database for data for a specified date for a set of specified stocks. So the data needs to have "this" date and be one of "these" symbols.
I have the following code:
public void findDateStockSet(String date, ArrayList<String> symbolSet) throws UnknownHostException {
this.stocks = this.getCollectionFromDB();
BasicDBObject objectToFind = new BasicDBObject();
List<BasicDBObject> obj = new ArrayList<BasicDBObject>();
obj.add(new BasicDBObject("date", date));
obj.add(new BasicDBObject("symbol", new BasicDBObject("$in", symbolSet)));
objectToFind.put("$and", obj);
DBCursor cursor = this.stocks.find(objectToFind);
System.out.println("Finding Stocks");
while (cursor.hasNext()) {
System.out.println(cursor.next());
}
System.out.println();
}
This always comes up null. Can someone explain how to make a query like this work?
You don't need to use $and operator, just build the query as the json below:
{ "date" : "20100223", "symbol" : { $in : [ "appl", "goog" ] } }
I like to use BasicDBObjectBuilder util class to build DBObjects. So your query will be:
DBObject query = BasicDBObjectBuilder.start()
.add("date", date)
.push("symbol")
.add("$in", symbolSet)
.get();

Categories

Resources