How to update a partial of nested document in mongoDB using java - java

Here is my document :
{ "_id" : ObjectId("5495cfcaec1e18b48015bba3"),
"Type" : "1",
"DomainSize" : "60",
"Metadata" : { "visit" : "3550",
"website" : "1",
"Specifics" : { "Size:" : "2",
"Type:" : "Janes",
"Closure Type:" : "Slip-On"},
"cat" : "2",
"function" : "6"},
"rate" : " 95.5% "}
I want to update few keys from Metadata which I don't know in advance.
My input is a Map of keys and values that exist inside the Metadata list.
I'm wrapping up the given map with another Map that the key is "Metadata" and the value the given map.
Map<String,Map<String,String>> metadata =new HashMap();
metadata.put("Metadata", values);
So I'm ending up with a
<"Metadata", Map<Key,Value>>
Then I used the following:
m_collection.update(new BasicDBObject("_id",id) , new BasicDBObject("$set", new BasicDBObject(metadata)));
The record update the existing keys inside the nested map adding '[]' to each value and deleting all the keys that are not been update.
For an example the given map is {'visit': '3558' , 'website' : '20'}.
After an updated I'm ending up with:
{ "_id" : ObjectId("5495cfcaec1e18b48015bba3"),
"Type" : "1",
"DomainSize" : "60",
"Metadata" : { "visit" : ["3558"],
"website" : ["20"]},
"rate" : " 95.5% "}
What did I do wrong?

You're calling $set on "metadata" which discards whatever is there and sets the new value with whatever you pass in. If you only want to partially update a document like that that, you'll either have to pass a complete document to reflect the new state or just issue $set updates: one for each field to change.

You need to use the dotted notation in the field names used for $set
See https://docs.mongodb.org/manual/tutorial/modify-documents/

Related

MongoDB nested query returning null with Java driver

I'm attempting to get the 'code' from the 'DEBIT' field from a mongodb collection formatted as follows:
"_id" : ObjectId("1"),
{...}
"bookEntryActions" : {
"CREATE" : [
{
"nature" : "DEBIT",
"code" : "123"
},
{
"nature" : "CREDIT",
"code" : "456"
}
],
"DELETE" : [
{
"nature" : "DEBIT",
"code" : "123"
},
{
"nature" : "CREDIT",
"code" : "789"
}
]
{...}
}
I've tried the following methods:
Method #1:
Document debitGlAccountCode = (Document)landlord.get("bookEntryActions.CREATE.1");
Method #2:
Document bookEntryActions = (Document) landlord.get("bookEntryActions");
Document creationRentCodes = (Document) bookEntryActions.get("CREATE");
ObjectId debitGlAccountCode = (ObjectId) creationRentCodes.get(Filters.eq("nature", "DEBIT"));
Method #3:
ObjectId debitGlAccountCode = (ObjectId) landlord.get(Filters.eq("bookEntryActions.CREATE.nature", "DEBIT"));
My issue is that of all the methods I've tried, the return for the .get("CREATE") is null. Does anyone have any idea what the issue could be? I've verified that the CREATE field exists for all of the landlords using Robo3T.
Edit: each variable has gotten the data as follows
final MongoCollection<Document> landlordCollection = db.getCollection("landlord");
final FindIterable<Document> landlordDocs = landlordCollection.find();
MongoCursor<Document> llDocIter = landlordDocs.iterator();
while(llDocIter.hasNext()){
Document landlord = llDocIter.next();
LOGGER.info("landlord bookEntryActions: " + landlord.get("bookEntryActions"));
LOGGER.info("landlord create: " + landlord.get("bookEntryActions.CREATE"));
landlordArrayList.add(landlord);
}
From there I have a foreach loop which goes through all the landlords in the arrayList and is where the previously attempted methods above are used. (Note: I'm using the array list for now as it's a little easier to work with while debugging. Eventually I will do everything in the while loop).
It turns out that the way the database was set up "CREATE" is an array list of documents and thus I had just been working with the wrong data types. Upon adapting the code to work with the arraylist and not a Document its working.

Fetch Inner Json of Array using Mongo Cursor

Using Cursor need to fetch values of Inner Json which is in Array
Document looks like this
{
"_id" : ObjectId("5772932ce4b0be6213704c81"),
"employerId" : "57728cd7e4b0be6213704b17",
"jobSeekerId" : "5706426ae4b0c7ea74fda18b",
"readByJobSeeker" : true,
"readByJobEmployer" : true,
"interestChat" : [
{
"userChat" : "is this job avaliable ",
"lastChatRole" : "JOBSEEKER",
"lastChatTime" : ISODate("2017-08-10T15:20:25.017Z"),
"jobSeekerAcknowledgeFlag" : true,
"connectionCounterIncreamented" : false
}
],
"createdDate" : ISODate("2016-06-28T15:09:32.564Z"),
"lastModifiedDate" : ISODate("2017-08-10T15:31:12.564Z"),
"version" : NumberLong(20),
"active" : true
}
Issue is using query
db.interest.find({"interestChat":{$exists:true}}).forEach(function(myChat){print ("interest :: "+ myChat.interestChat); } ).pretty()
Not able to fetch data from Array as output come out as
interest :: [object BSON]
Need to fetch values of Inner json
The function print is not meant to bring json/bson objects.
Try printjson instead.
db.interest.find({"interestChat":{$exists:true}})
.forEach(function(myChat){
printjson({"interest": myChat.interestChat});
})
OR just printjson(myChat.interestChat);

$set does not change the value of the field in java driver for mongodb

My collection is something like this:
{
"_id" : ObjectId("597c4c42398593a7b464fc9c"),
"userId" : NumberLong(2),
"steps" : [
{
"_id" : ObjectId("597c4c42398593a7b464fc9a"),
"beginningDate" : "2017-07-29T13:20:10.344",
"state" : "Pending",
"messages" : [
{
"_id" : ObjectId("597c4c42398593a7b464fc9b"),
"content" : "Hi",
"isRead" : 0,
"side" : "UserToAdmin",
"creationDate" : "2017-07-29T13:20:10.344"
}
]
},
{
"_id" : ObjectId("597c4ce5398593aaa897ccb4"),
"beginningDate" : "2017-07-29T13:22:53.884",
"state" : "Open",
"messages" : []
}
],
"lastStepState" : "Pending",
"lastModified" : "2017-07-29T13:26:36.774"
}
What I'm basically trying to do is whenever I push a new step into the steps array, I update the lastStepState in the following way:
Document updateQueryDoc = new Document("userId", userId).append("lastStepState",
new Document("$eq", State.Pending.name()));
Document updateDoc = new Document("$push", new Document("steps", newStepDoc))
.append("$set", new Document("lastStepState", State.Open.name()))
.append("$set", new Document("lastModified", now));
(State is an enum with Pending and Open values)
However, the lastStepState does not gets updated. what could be the problem?
(I also should mention that there is one document in the collection, so using updateMany is not a soultion to my problem.)
Document's append uses the underlying Map's put(K key, V value) function, so when you call append("$set", new Document("lastModified", now)) it overwrites the value of the previously set $set key.
You can fix it like this:
Document updateDoc = new Document("$push", new Document("steps", newStepDoc))
.append("$set", new Document("lastStepState", State.Open.name()).append("lastModified", now));

Retrieve all the documents matching the criteria in an array elements which is a subdocument

{
"_id" : ObjectId("577b54816081dd32cd3e2d60"),
"user" : ObjectId("577b54816081dd32cd3e2d5e"),
"journals" : [
{
"title" : "Journal Title2",
"desc" : "desx2",
"feeling" : 3,
"date" : ISODate("2016-07-05T06:32:45.404Z"),
"deleteFl" : true,
"_id" : ObjectId("577b548d6081dd32cd3e2d64")
},
{
"title" : "Journal Title3",
"desc" : "desx3",
"feeling" : 3,
"date" : ISODate("2016-07-05T06:49:00.156Z"),
"deleteFl" : false,
"_id" : ObjectId("577b585c6081dd32cd3e2d6d")
},
{
"title" : "Journal Title4",
"desc" : "desx4",
"feeling" : 3,
"date" : ISODate("2016-07-05T06:49:06.700Z"),
"deleteFl" : false,
"_id" : ObjectId("577b58626081dd32cd3e2d70")
}
]
}
Above is my document structure
now, I need all the journal documents whose deleteFl = false.
I tried in this way using Java Mongo driver
getDatabase().getCollection("journals").find(and(eq("user", user), eq("journals.deleteFl", false)));
but still it gives me back all the documents including "deleteFl": true. any help here ?
Actually, your query returns 1 document, because the data is inside 1 document. What you want is to limit the returning fields of a document (limit subdocuments).
Note: You can do that using elemMatch in the projection, to limit the fields returned by the query. But elemMatch will return just one subdocument. (I posted a deleted wrong answer using elemMatch)
When you want all subdocuments and only specific subdocuments from inside an array, you need to use the aggregation pipeline.
Here is a tested code that does what you want (just change DB and colelction name):
MongoClient mongoClient = new MongoClient();
MongoDatabase db = mongoClient.getDatabase("test");
MongoCollection collection = db.getCollection("test");
Iterable<Document> output = collection.aggregate(asList(
new BasicDBObject("$unwind", "$journals"),
new BasicDBObject("$match", new BasicDBObject("journals.deleteFl", false))
));
for (Document dbObject : output)
{
System.out.println(dbObject);
}

MongoDB update element of nested array

I have a mongo collection named firma which has one of the document structure as below:
{
"_id" : ObjectId("5729af099b3ebf1d0ca7ff05"),
"musteriler" : [
{
"_id" : "de0bf813-b707-4a8d-afc2-9752e05c3aa5",
"yetkiliListesi" : [
{
"_id" : "a5e487fa-2034-4817-94f2-3bd837b76284",
"ad" : "Burak",
"soyad" : "Duman 1",
"cepTel" : "3333333333333",
"mail" : "asdf#asdf.com"
},
{
"_class" : "com.bisoft.entity.MusteriYetkili",
"_id" : "bc4b537d-522a-4c9a-9f67-8ca243e18f46",
"ad" : "Ridvan",
"soyad" : "ENİŞ",
"cepTel" : "222222222222",
"mail" : "asdf#asdf.com"
}
]
}
],
"defaultTimezone" : "Europe/Istanbul"
}
In the above json, I need to update element of second array(yetkiliListesi) which _id = "a5e487fa-2034-4817-94f2-3bd837b76284"
Since I am using a java application(using mongo java driver and spring boot MongoTemplate) to access it and execute this query :
mongoTemplate.updateFirst(Query.query(Criteria.where("_id").is("5729af099b3ebf1d0ca7ff05").and("musteriler.yetkiliListesi._id").is("a5e487fa-2034-4817-94f2-3bd837b76284")),
new Update().set("musteriler.yetkiliListesi.$", yetkiliDBO), Firma.class);
In the above query, yetkiliDBO is a BasicDBObject and its content :
yetkiliDBO = {
'_class': 'com.bisoft.entity.MusteriYetkili',
'_id': "a5e487fa-2034-4817-94f2-3bd837b76284",
'ad': 'wer',
'soyad': 'xyz',
'cepTel': "222222222222",
mail: "asdf#asdf.com"
}
when execute my query I have an error
com.mongodb.WriteConcernException: { "serverUsed" : "192.168.2.250:27017" , "ok" : 1 , "n" : 0 , "updatedExisting" : false , "err" : "cannot use the part (musteriler of musteriler.yetkiliListesi.0) to traverse the element
What I need to do?
You can not use the '$' placeholder when traversing nested arrays.
The positional $ operator cannot be used for queries which traverse more than one array, such as queries that traverse arrays nested within other arrays, because the replacement for the $ placeholder is a single value
source
I would suggest restructuring your data into separate, less-nested collections.

Categories