update in sharded environment with JAVA - java

I am trying to update a filed 'Content' of a document in sharded environment. My shard key is 'asset' which is included in the query. But I am getting error saying
"com.mongodb.WriteConcernException: { "serverUsed" :
"/10.102.10.190:27017" , "err" : "update { q: { $and: [ { asset:
\"/1/01/01.m3u8\" }, { recList: \"REC-1-1418208180000-1418208300000\"
} ] }, u: { $set: { Content: BinData } }, multi: false, upsert: false
} does not contain _id or shard key for pattern { asset: 1 }" , "code"
: 61 , "n" : 0 , "shards" : [ ] , "shardRawGLE" : { } , "ok" : 1.0} "
BasicDBObject newDocument = new BasicDBObject();
newDocument.append("$set", new BasicDBObject().append("Content", content));
BasicDBObject andQuery = new BasicDBObject();
List<BasicDBObject> obj = new ArrayList<BasicDBObject>();
obj.add(new BasicDBObject("asset", assetf));
obj.add(new BasicDBObject("recList", recId));
andQuery.put("$and", obj);
WriteResult result = collection.update(andQuery, newDocument);
Please help me.

Related

"or" condition in embedded document java

What is the correct syntax for creating $or condition in embedded document in MongoDB Java driver?
Is it actually possible to get a cursor to embedded documents?
Suppose I have the following document:
{
statuses: [{
{
streamName: A
}{
statusA: 0
}{
statusB: 1
}
},
{
{
streamName: B
}{
statusA: 0
}{
statusB: 1
}
}]
}
I would also like to get cursor to sub documents (in array of statuses) that has at least one status bigger than 0.
This is how I did it but it didn't work:
List<BasicDBObject> obj = new ArrayList<BasicDBObject>();
DBObject query = new BasicDBObject();
obj.add(new BasicDBObject ("statuses",
new BasicDBObject ("statusA",
new BasicDBObject ("$gt",0 ) )));
obj.add(new BasicDBObject ("statuses",
new BasicDBObject ("statusB" ,
new BasicDBObject ("$gt",0 ) )));
query.put("$or",obj)
db.find(collectionName,query)
I didn't find any documentation on that.
What you have translates to
{ "$or" : [ { "statuses" : { "statusA" : { "$gt" : 0}}} , { "statuses" : { "statusB" : { "$gt" : 0}}}]}
which is used for whole document comparison.
For comparing fields inside an embedded arrays/doc you've to use dot notation.
{ "$or" : [ { "statuses.statusA" : { "$gt" : 0}} , { "statuses.statusB" : { "$gt" : 0}}]}
The equliavent java code is below
List<BasicDBObject> obj = new ArrayList<BasicDBObject>();
DBObject query = new BasicDBObject();
obj.add(new BasicDBObject ("statuses.statusA", new BasicDBObject ("$gt",0 ) ));
obj.add(new BasicDBObject ("statuses.statusB" , new BasicDBObject ("$gt",0 ) ));
query.put("$or",obj);
Alternatively you can use $elemMatch to run matches on embedded arrays. Similar to what you've but $elemMatch applies condition to each fields.
Something like
{ "statuses" : { "$elemMatch" : { "$or" : [ { "statusA" : { "$gt" : 0}} , { "statusB" : { "$gt" : 0}}]}}}
Java Code
BasicDBList obj = new BasicDBList();
obj.add(new BasicDBObject ("statusA",new BasicDBObject ("$gt",0 ) ));
obj.add(new BasicDBObject ("statusB",new BasicDBObject ("$gt",0 ) ));
DBObject query = new BasicDBObject("statuses", new BasicDBObject("$elemMatch", new BasicDBObject("$or",obj)));
Count the no of matching occurrences.
Bson count = new Document("statuses", Document.parse("{$size:{\n" +
" $filter: {\n" +
" input: \"$statuses\",\n" +
" as: \"status\",\n" +
" cond: { \"$or\" : [ {$gt:[\"$$status.statusA\", 0]} , {$gt:[\"$$status.statusB\", 0]}]}\n" +
" }\n" +
" }}"));
Bson project = new Document("$project", count);
col.aggregate(Arrays.asList(project));

How to pass list of generic fields with their corresponding first operator to Aggregation.group method

I want to write a generic code for aggregation using mongoTempalte and Aggregation.group() method. So I have the problem of passing generic fields into the group method with the first() operator
here is my demo native query as follows:
db.subscriberProfile.aggregate([{"$unwind":"$usage_history"},
{ "$group" : { "_id" :"$_id" ,"birthdate" : { "$first":"$birthdate"} , "category" : { "$first":"$category"} , "control_group" : { "$first":"$control_group"} , "sumOfTotalUsage" : { "$sum" :{"$cond": [ { "$gte" :[ "$usage_history.date" , ISODate( "2017-01-13T10:43:55.306Z")] }, "$usage_history.total_usage", 0]}}}},
{ "$match" : { "$and" : [ { "birthdate" : { "$lte" : ISODate( "2017-07-12T10:43:55.306Z")}} , { "birthdate" : { "$gte" : ISODate( "1917-07-12T10:20:35.306Z")}} , { "category" : { "$in" : [ "Prepaid"]}} , { "control_group" : false} , { "sumOfTotalUsage" : { "$gte" : 0}}]}}])
And here is my Sample code in Java.
UnwindOperation unwind = Aggregation.unwind("usage_history");
GroupOperation group = Aggregation.group(fields.toArray(new String[fields.size()])).sum("usage_history.total_usage").as("sumOfTotalUsage");
I just want to know how to add multiple fields in group operation with $first operator.
So, Is there any way to pass list of fields with list of first operator to the group method.
Thanks,
Try this code,I hope this will help you
UnwindOperation unwind = Aggregation.unwind("usage_history");
BasicDBObject object = new BasicDBObject("_id", "$_id");
for (String string : fields) {
object.append(string, new BasicDBObject("$first", "$" + string));
}
object.append("total", new BasicDBObject("$sum", new BasicDBObject("$cond",
new Object[] { new BasicDBObject("$gte", new Object[] { "$usage_history.date", calendarMin.getTime() }),
"$usage_history.total_usage", 0 })));
BasicDBObject groupObject = new BasicDBObject("$group", object);
DBObject groupOperation = (DBObject) groupObject;
MatchOperation matchMain = Aggregation
.match(new Criteria().andOperator(criteriaList.toArray(new Criteria[criteriaList.size()])));
Aggregation aggregation = Aggregation.newAggregation(unwind, new CustomGroupOperation(groupOperation),
matchMain);

MongoDB Java Driver updates unmatched sub-document

I'm using mongo-java-driver:3.3.0 and trying to update one value of my sub-document using $inc operator and findOneAndUpdate, but only under certain conditions (id comparison and greaterThan filter).
Following is a snippet to reproduce the problem:
MongoCollection<Document> coll = db.getCollection("update_increase");
Document docBefore = new Document()
.append("subdocs", Arrays.asList(
new Document("id", "AAA").append("count", 10),
new Document("id", "BBB").append("count", 20)
));
coll.insertOne(docBefore);
Document filter = new Document()
.append("subdocs.id", "BBB")
.append("subdocs.count", new Document("$gt", 7));
Document update = new Document()
.append("$inc", new Document("subdocs.$.count", -7));
Document docAfter = coll.findOneAndUpdate(
filter,
update,
new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER));
docBefore:
{ "_id" : { "$oid" : "5819c85977a8cb12f8d706c9" },
"subdocs" : [
{ "id" : "AAA", "count" : 10 },
{ "id" : "BBB", "count" : 20 }
]
}
docAfter:
{ "_id" : { "$oid" : "5819c85977a8cb12f8d706c9" },
"subdocs" : [
{ "id" : "AAA", "count" : 3 },
{ "id" : "BBB", "count" : 20 }
]
}
What I expected is count:13 on the second subdoc (id:"BBB"), but I got an update on the first one (count:3).
This works fine if I remove greaterThan condition line (.. new Document("$gt", 5) ..):
{ "_id" : { "$oid" : "5819c92577a8cb13404cfc91" },
"subdocs" : [
{ "id" : "AAA", "count" : 10 },
{ "id" : "BBB", "count" : 13 }
]
}
What I'm doing wrong?
Thanks!
Here is the java equlivant for $elemMatch.
Document filter = new Document("subdocs", new Document().append("$elemMatch", new Document().append("id", "BBB").append("count", new Document("$gt", 7))));

Java MongoClient - Type exceptions when using Aggregate

I am getting the following exception:
com.mongodb.CommandFailureException: { "serverUsed" : "192.168.3.25:27017" ,
"errmsg" : "exception: The argument to $size must be an Array,
but was of type: EOO" , "code" : 17124 , "ok" : 0.0}
Whenever I run this pipeline using the MongoClient driver for Java:
[{ "$match" : { "_id" : "1"}}, { "$project" : { "count" : { "$size" : "$tags"}}}]
What is causing this? The pipeline works fine in the Mongo shell?
Here is my Java code:
private void countArrayLength(String id, String arrayName) {
AggregationOptions options = AggregationOptions.builder().build();
DBObject matchFields = new BasicDBObject("_id", id);
DBObject match = new BasicDBObject("$match", matchFields);
DBObject projectCount = new BasicDBObject("$size", "$" + arrayName);
DBObject projectFields = new BasicDBObject("count", projectCount);
DBObject project = new BasicDBObject("$project", projectFields);
Cursor cursor = db.getCollection(collectionName)
.aggregate(asList(match, project), options);
}
DB Structure:
{
"_id" : "1",
"_class" : "com.mongodb.BasicDBObject",
"tags" : [
{
"tag" : "tagName"
},
{
"tag" : "tagName"
},
{
"tag" : "tagName"
},
{
"tag" : "tagName"
},
{
"tag" : "tagName"
}
]
}

Add new field to mongoDB embeded Doc

I have a mongo Document structure like this with comments field as embedded doc.
i want to add "newField" : "something" to embedded comments field with "cid" : "17426944" :
in java driver i tried :
BasicDBObject query = new BasicDBObject(); // MongoDB query
BasicDBObject record = new BasicDBObject(); // MongoDB record
BasicDBObject dbObject = new BasicDBObject(); // fieldsToUpdate
query.put("comments.cid","17426944");
dbObject.put("comments.newField","something");
record.put("$set",dbObject );
mongoCtrl.updateCollection(query, record, false, true); // mongoCtrl is my connection contrl
problem here is :
com.mongodb.MongoException: cannot use the part (comments of comments.newField) to traverse the element ({comments:[ .......... ]})
at com.mongodb.CommandResult.getException(CommandResult.java:100)
at com.mongodb.CommandResult.throwOnError(CommandResult.java:134)
at com.mongodb.DBTCPConnector._checkWriteError(DBTCPConnector.java:142)
sample doc :
{
"_id" : ObjectId("53abb8d17bfd6b92e2398d34"),
"name" : "satish",
"number": "1122112",
"comments" : [
{
"cid" : "17426944"
},
{
"cid" : "607395840"
},
{
"cid" : "393084416"
}
]
}
what i need :
{
"_id" : ObjectId("53abb8d17bfd6b92e2398d34"),
"name" : "satish",
"number": "1122112",
"comments" : [
{
"cid" : "17426944",
"newField" : "something"
},
{
"cid" : "607395840"
},
{
"cid" : "393084416"
}
]
}
Plz help me.Thanks vijay
Pretty close, you just missed the positional $ operator to match the position of the array found in your query portion:
BasicDBObject query = new BasicDBObject(); // MongoDB query
BasicDBObject record = new BasicDBObject(); // MongoDB record
BasicDBObject dbObject = new BasicDBObject(); // fieldsToUpdate
query.put("comments.cid","17426944");
dbObject.put("comments.$.newField","something");
record.put("$set",dbObject );
mongoCtrl.updateCollection(query, record, false, true);

Categories