Update Mongo nested array using Java with multiple conditions - java

I have following document :
{
"_id" : ObjectId("5d42501efbf6f6108277ceb3"),
"customer" : {
"id" : "02c59458-8f0a-4a11-bff6-55b4710bc546",
"name" : "brookfield"
},
"userId" : "86c241de-16de-417d-8537-ed441fee9b0e",
"username" : "Fonville_f888f976_un_",
"userGroups" : [],
"lastSeen" : ISODate("2020-05-06T20:21:49.140Z"),
"devices" : [
{
"id" : "A920B6F24B63479B8796B709EA542951",
"displayId" : "A920B6F24B63479B8796B709EA542951",
"manufacturedId" : false,
"lastSeen" : ISODate("2020-03-20T14:36:24.961Z"),
"product" : {
"manufacturer" : "PSman",
"manufacturerCode" : 10,
"name" : "BlackHawk 880 series",
"modelId" : "C053"
}
},
{
"id" : "2476B0E045712cc-5904-11ea-af28-0612af3fc862",
"displayId" : "2476B0E16929512870992618563",
"lastSeen" : ISODate("2020-01-09T20:59:48.650Z"),
"product" : {
"manufacturer" : "GN",
"manufacturerCode" : 5,
"name" : "Telenor Speak 710",
"modelId" : "2476",
"vendorId" : "B0E"
}
}
],
"software" : {
"applicationId" : "f81d4fae-7dec-11d0-a765-00a0c91e6bf6",
"version" : "3.12.52334.30629",
"displayVersion" : "3.12.0"
},
"lastHost" : {
"name" : "hn_5934d3c5dbf",
"platform" : "WIN",
"osVersion" : "10.0.17763"
}
}
I have to update every product name inside devices array based on product modelId field.
So, user will pass two modelId values and if one of them match product's modelId than product name for that product should be updated.
I wrote following code, and I tested it with mongo db version 4.2, and it works. The problem is that when i tested it with older version of mongo db (3.4.23), it doesn't work,and I'm getting following exception :
com.mongodb.MongoCommandException: Command failed with error 9 (FailedToParse): 'Unrecognized field in update operation: arrayFilters' on server localhost:27017. The full response is { "ok" : 0.0, "errmsg" : "Unrecognized field in update operation: arrayFilters", "code" : 9, "codeName" : "FailedToParse" }
Here is how my method looks like :
private void updateCollection(String firstPid,String secondPid, String newProductName) {
MongoCollection<Document> collection = mongoTemplate.getCollection("user");
BasicDBObject searchQueryOne = new BasicDBObject();
BasicDBObject searchQueryTwo = new BasicDBObject();
BasicDBList or = new BasicDBList();
BasicDBObject query = new BasicDBObject("$or", or);
BasicDBObject updateQuery = new BasicDBObject();
searchQueryOne.append("devices.product.modelId", firstPid);
searchQueryTwo.append("devices.product.modelId", secondPid);
or.add(searchQueryOne);
or.add(searchQueryTwo);
updateQuery.append("$set",
new BasicDBObject().append("devices.$[elem].product.name", newProductName));
collection.updateMany(query, updateQuery, new UpdateOptions().arrayFilters(
Collections.singletonList( Filters.in("elem.product.modelId", Arrays.asList(firstPid,secondPid)))));
}
Please help

After some resarching, I managed to solve my problem. If someone have similar issue, here is the code that worked for me
public void updateUserCollection(String pidOne, String pidTwo) {
MongoCollection<Document> userCollection = mongoTemplate.getCollection("user");
BasicDBObject deviceCriteria = new BasicDBObject("devices.product.modelId", new BasicDBObject("$in", Arrays.asList(pidOne)));
FindIterable<Document> cursor = userCollection.find(deviceCriteria);
MongoCursor<Document> iterator = cursor.iterator();
while (iterator.hasNext()) {
Document user = iterator.next();
String userId = user.get("userId", String.class);
List<Document> devices = user.get("devices", List.class);
for (Document device : devices) {
Document product = device.get("product", Document.class);
String modelId = product.get("modelId", String.class);
if (modelId != null && (modelId.equals(pidOne) || modelId.equals(pidTwo))) {
product.put("name", newProductName);
}
}
saveUser(userId, user, userCollection);
}
iterator.close();
}
private void saveUser(String userId, Document user, MongoCollection<Document> userCollection) {
BasicDBObject updateQuery = new BasicDBObject("$set", user);
BasicDBObject searchQuery = new BasicDBObject("userId", userId);
userCollection.updateMany(searchQuery, updateQuery);
}

Related

Mongo Template's findAndModify is returning null values for adding or updating nested elements

My data is formatted as:
{
"_id" : "149",
"books" : {
"32" : "0.12",
"33" : "0.21"
}
}
I would like to update/insert values inside the nested books document. If I insert a new row say "39" : "0.19", then the updated document should look as below:
{
"_id" : "149",
"books" : {
"32" : "0.12",
"33" : "0.21",
"39" : "0.19"
}
}
And updates should work, the way they are meant to work. By updating the values.
I tried several ways, but couldn't update the way I wanted.
Method1: Working but wrong result
MongoCollection<Document> document = mongoTemplate.getCollection("booksCollection");
BasicDBObject query = new BasicDBObject();
query.put("_id", storeId);
BasicDBObject bookDiscount = new BasicDBObject();
bookDiscount.put(bookId, discount);
BasicDBObject update = new BasicDBObject();
update.put('$push', new BasicDBObject("books", bookDiscount));
document.findOneAndUpdate(query, update);
Method1 Output: Each value is added in a new row
{
"_id" : "1664",
"books" : [
{
"28" : NumberDecimal("0.75")
},
{
"29" : NumberDecimal("0.18")
},
{
"30" : NumberDecimal("0.23")
},
{
"245" : NumberDecimal("0.26")
},
{
"277" : NumberDecimal("0.13")
},
{
"270" : NumberDecimal("0.19")
}
]
}
Method2: Working but wrong result
MongoCollection<Document> document = mongoTemplate.getCollection("booksCollection");
BasicDBObject query = new BasicDBObject();
query.put("_id", storeId);
BasicDBObject bookDiscount = new BasicDBObject();
bookDiscount.put(bookId, discount);
BasicDBObject update = new BasicDBObject();
update.put('$set', new BasicDBObject("books", bookDiscount));
document.findOneAndUpdate(query, update);
Method2 Output: Value always gets replaced
{
"_id" : "16644158",
"locationInfRate" : {
"2857" : NumberDecimal("0.68")
},
"_class" : "com.test.books"
}
What I learned:
$push method pushes the data as a member of a list.
$set method updates the data, but for maps, it replaces data if the map is not correctly formatted in the query.
I edited my $set query to below format and it worked:
MongoCollection<Document> document = mongoTemplate.getCollection("booksCollection");
BasicDBObject query = new BasicDBObject();
query.put("_id", storeId);
BasicDBObject bookDiscount = new BasicDBObject();
bookDiscount.put("books." + bookId, discount);
update.put('$set', bookDiscount);
document.findOneAndUpdate(query, update);

Mongodb - update specific array element

I have a collection "prefs" with document structure as below
{
_id: {
userId: "abc"
},
val: {
status: 1,
prefs: [
{
value: "condition",
lastSent: ISODate("2017-07-17T23:46:53.717Z")
}
],
deal: 2,
prevDeal: 3
}
}
I am trying to update the date field lastSent with a condition on userId and status. Below are the queries that I derieved from my Java code.
Select Query:
{ "_id" : { "userId" : "abc"} , "val.status" : 1 , "val.prefs.value" : "condition"}
Update Query:
{ "$set" : { "val.prefs.$.lastSent" : { "$date" : "2017-07-17T23:50:07.009Z"}}}
The above query is giving error as follows:
The dotted field 'prefs.$.lastSent' in 'val.prefs.$.lastSent' is not valid for storage.
How do I achieve this?
Below is my Java code:
BasicDBObject _idObject = new BasicDBObject();
_idObject.put("userId", "abc");
BasicDBObject _selectQuery = new BasicDBObject();
_selectQuery.put("_id", _idObject);
_selectQuery.put("val.status", 1);
_selectQuery.put("val.prefs.value", "condition");
BasicDBObject _valueUpdateQuery = new BasicDBObject();
_valueUpdateQuery.put("prefs.$.lastSent", lastSent);
BasicDBObject _updateQuery = new BasicDBObject();
_updateQuery.put("$set", new BasicDBObject("val", _valueUpdateQuery));
prefs.update(_selectQuery, _updateQuery, true, true);
I just tested with your code in mongo shell this codes works fine you don't have to mention
$date
and i used this code for updating date
db.getCollection('tester').update({ "_id" : { "userId" : "abc"} , "val.status" : 1 , "val.prefs.value" : "condition"},{ "$set" : { "val.prefs.$.lastSent" : new Date()}})

Query from Vava to MongoDB: find event in a specific date range

I've got the following document in MongoDB:
{
"_id" : NumberLong(44),
"_class" : "la.test.app.server.model.Event",
"orgId" : NumberLong(2),
"typeCode" : 1,
"title" : "Test for notification",
"shortDescription" : "Test for notification",
"description" : "Test for notification",
"price" : "100",
"startDate" : ISODate("2015-02-08T16:30:07.000Z"),
"endDate" : ISODate("2015-02-09T16:00:07.000Z"),
"deleted" : false
}
I need to find this event among all others.
I'm trying to do such a simple thing with method:
public List<Event> getPendingEvents(Date start, Date end) {
return mongoOperations.find(
Query.query(Criteria
.where("startDate").gte(start).lte(end)
.and("typeCode").is("1")),
Event.class
);
That assembles and returns me query:
{
"startDate" : { "$gte" : { "$date" : "2015-02-08T05:29:00.000Z"} ,
"$lte" : { "$date" : "2015-02-08T05:31:00.000Z"}} ,
"typeCode":"1"
}
And this query finds just "Fields: null, Sort: null":
But a direct query to MongoDB:
db.events.find({
"startDate" : {"$gte" : ISODate("2015-02-08 16:30:07.000Z"),
"$lt" : ISODate("2015-02-08 16:31:07.000Z")},
"typeCode" : 1})
Finds the required event.
Did you tried by formating the date by using SimpleDateFormat...?
I had tried this long back...
// Find documents by date of birth
Date gtDate = null;
try {
gtDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").parse("1984-05-010T8:30:00.000Z");
} catch (ParseException e) {
e.printStackTrace();
}
BasicDBObject dateQueryObj = new BasicDBObject("DateOfBirth", new BasicDBObject("$lt", gtDate));
cursor = documents.find(dateQueryObj);
while(cursor.hasNext()) {
System.out.println("\n Find documents by date of birth. \n");
System.out.println(cursor.next());
}
Same problem was solved by using BasicDBObject instead of a mongoOperations intreface.
Something like that:
BasicDBObject query = new BasicDBObject();
query = new BasicDBObject("endDate", new BasicDBObject("$gte", start).append("$lte", end)).append("typeCode", 1);
List<DBObject> result = collection.find(query).toArray();

MongoDB Array modify Using Java

I am new to MongoDB, I want to remove an element from array structure as shown below:
{
"Data" : [
{
"url" : "www.adf.com"
"type":7
},
{
"url" : "www.pqr.com"
"type":2
}
{
"url" : "www.adf.com"
"type":3
},
{
"url" : "www.pqr.com"
"type":5
}
],
}
I want to remove url=www.adf.com which has type as lowest values i.e in this document my query should remove type=3 and return document as below:
{
"Data" : [
{
"url" : "www.adf.com"
"type":7
},
{
"url" : "www.pqr.com"
"type":2
}
{
"url" : "www.pqr.com"
"type":5
}
],
}
The query shown by #shakthydoss can be described in java as follows:
MongoClient mongoClient = new MongoClient("SERVER", 27017);
DB db = mongoClient.getDB("DB_NAME");
DBCollection coll1 = db.getCollection("COLLECTION_NAME");
DBObject eleMatch = new BasicDBObject();
eleMatch.put("url", "www.pqr.com");
eleMatch.put("type", new BasicDBObject("$lte", 50));
BasicDBObject up = new BasicDBObject();
up.put("$elemMatch", eleMatch);
BasicDBList basicDBList = new BasicDBList();
basicDBList.add(up);
DBObject query = new BasicDBObject("Data", new BasicDBObject(" $all", basicDBList));
coll1.find(query);
Use $all with $elemMatch
If the field contains an array of documents, you can use the $all with the $elemMatch operator.
db.inventory.find( {
Data: { $all: [
{ "$elemMatch" : { url : "www.pqr.com": "M", type: { $lte: 50} } },
] }
} )

MongoDb accesing nested documents in java

I am new to MongoDB. I am trying to access nested doc in mongodb. My sample doc is
{
"Advertisement" : {
"html" : "zxcxz"
},
"Notification" : {
"date_from" : ISODate("2013-06-30T18:30:00Z"),
"date_too" : ISODate("2013-07-16T18:30:00Z"),
"description" : "vcvc",
"url" : "vcvc"
},
"_id" : ObjectId("51e4f10ee4b08e0a6ebcbe46"),
"group_name" : "sumit",
"target_audience" : {
"gender" : "male",
"section" : "xyz",
"catagory" : "--Computer--",
"location" : {
"country" : "--Country--",
"state" : "--State--",
"city" : "--City--"
}
}
}
I am trying to get gender from target_audience. My java code is
DBCursor f=con.coll.find(query);
while(f.hasNext())
{
f.next();
gender=(String) f.curr().get("target_audience.gender");
}
But it returns null.
The result of DBCursor.next() and DBCursor.curr() is a BasicDBObject. For keys with embedded documents, BasicDBObject.get(key) returns a BasicDBObject
DBCursor f=con.coll.find(query);
while(f.hasNext())
{
BasicDBObject result = (BasicDBObject) f.next();
BasicDBObject target = (BasicDBObject) result.get("target_audience");
gender = (String) target.get("gender");
}

Categories

Resources