Accessing sub doccuments from array in mongoDB - java

this is my sampale mongo doc.
"Notification" : [
{
"date_from" : ISODate("2013-06-30T18:30:00Z"),
"date_too" : ISODate("2013-07-23T18:30:00Z"),
"description" : "bbbbbbbbbbbbbbb",
"url" : "bbbbbbbbbbbbbb"
},
{
"date_from" : ISODate("2013-07-07T18:30:00Z"),
"date_too" : ISODate("2013-07-16T18:30:00Z"),
"description" : "ddd",
"url" : "ddd"
},
{
"date_from" : ISODate("2013-07-02T18:30:00Z"),
"date_too" : ISODate("2013-07-29T18:30:00Z"),
"description" : "cccc",
"url" : "cccccccccccccc"
}
],
I am trying to access "Notifications":array having 3 sub documents. I want to retrieve each document individually.
My java code is
notification=(BasicDBList) f.curr().get("Notification");
Any help is appreciated.

BasicDBList extends BasicBSONList, which in turn, extends ArrayList. You can get individual elements from the list using their index.
BasicDBList notifications = (BasicDBList) cursor.curr().get("Notification");
BasicDBObject first = (BasicDBObject) notifications.get(0); //first document
BasicDBObject second = (BasicDBObject) notifications.get(1); //second document
BasicDBObject third = (BasicDBObject) notifications.get(2); //third document
System.out.println(first.get("description")); // bbbbbbbbbbbbbbb
System.out.println(second.get("url")); // bbbbbbbbbbbbbb
You may instead want to iterate over them:
for(Object o : notifications) {
BasicDBObject obj = (BasicDBObject) o;
System.out.println(obj.get("url")); //prints the URL of every document in notifications
}

Related

Count document MongoDB java

I am new to MongoDB and I am finding rather complicated to count the child number of my nested documents.
This is part of my 'users' collection.
"_id" : ObjectId("58f9f7a91fb2bf7c46abe5d6"),
"name" : "fernando guima",
"premium" : true,
"email" : "lolol#loladamix.com",
"creationDate" : ISODate("2017-04-21T12:14:33.970Z"),
"playlists" : [
{
"name" : "minha Playlist",
"creationDate" : ISODate("2017-04-21T12:14:33.982Z"),
"videos" : [
{
"video_id" : "video1",
"creationDate" : ISODate("2017-04-21T13:00:38.461Z")
},
{
"video_id" : "video2",
"creationDate" : ISODate("2017-04-21T13:00:38.502Z")
}
]
},
{
"name" : "minha Playlist 2",
"creationDate" : ISODate("2017-04-21T12:14:33.983Z"),
"videos" : [ ]
}
]
}
I want to be able to retrieve the number of 'videos' in my 'playlist' (playlist childs) and retrieve a video data, how can I do that?
I wrote the following code that adds a video to a given playlist:
public void addToPlaylist(String parameter, String value, String playListName, String video_id){
//user document
BasicDBObject query = new BasicDBObject(parameter, value);
//First it fetches the wanted document by a parameter and its value e.g, (name, Fernando)
BasicDBObject mObject = new BasicDBObject();
mObject.put("video_id", video_id);
mObject.put("creationDate", new Date());
BasicDBObject updateObj = new BasicDBObject();
//falta percorrer o array das playlists para encontrar o id pelo nome da playlist
updateObj.put("$push", new BasicDBObject("playlists."+"0"+".videos", mObject));
mMongo.getCollection("users").updateOne(query, updateObj);
}
I expect to receive, {videos : 2} as the number of videos in my first playlist. And some output about video data like: {"video_id" : "video1"}
Regards
You can use below query. The query will $match to select the document followed by $unwind of playlists array and $project to reach videos array to calculate its $size and extract video_id.
MongoClient client = new MongoClient("localhost", 27017);
MongoDatabase database = client.getDatabase("db");
MongoCollection<Document> collection = database
.getCollection("collection");
Bson filter = Filters.eq("_id", new ObjectId("58f9f7a91fb2bf7c46abe5d6"));
List<VideoResult> results = collection.aggregate(Arrays.asList(Aggregates.match(filter), Aggregates.unwind("$playlists"), Aggregates.project(Projections.fields(Arrays.asList(Projections.computed("videos", new Document("$size","$playlists.videos")),
Projections.computed("video_ids", "$playlists.videos.video_id")))))).map(VideoResult::new).into(new ArrayList<>());
Output:
{
"_id" : ObjectId("58f9f7a91fb2bf7c46abe5d6"),
"videos" : 2,
"video_ids" : [
"video1",
"video2"
]
}
{
"_id" : ObjectId("58f9f7a91fb2bf7c46abe5d6"),
"videos" : 0,
"video_ids" : [ ]
}
Pojo:
public class VideoResult {
private int videos;
private List<String> videoIds;
public VideoResult(Document doc) {
this.videos = doc.getInteger("videos");
this.videoIds = (List<String>) doc.get("video_ids");
}
// getters and setters
}
Another solution, MongoDB 3.4
db.users.aggregate([
{$unwind: '$playlists'}, {$addFields: {'playlists.id': '$_id'}},
{$replaceRoot: {newRoot: '$playlists'}},
{$unwind: {path: '$videos', preserveNullAndEmptyArrays: true}},
{$group: {_id: {name: '$name', creationDate: '$creationDate', _id: '$id'},
video_ids: {$push: '$videos.video_id'},
videos: {$sum: {$cond: [{$ifNull: ['$videos', 0]}, 1, 0]}}}},
{$addFields: {_id: '$_id._id'}}])
Output:
{
"_id" : ObjectId("58f9f7a91fb2bf7c46abe5d6"),
"video_ids" : [ ],
"videos" : 0
}
{
"_id" : ObjectId("58f9f7a91fb2bf7c46abe5d6"),
"video_ids" : [
"video1",
"video2"
],
"videos" : 2
}

Update a nested document filed and increment in mongodb

I want to update a nested document filed if present increment an old value with new value or insert a new document.
Data
New Zealand,Waikato,Hamilton,1004
New Zealand,Waikato,Auckland,145
New Zealand,Otago,Dunedin,1068
Json
{ "_id" : ObjectId("55e7d2a72f68907c17cfcb2f"), "country" : "New Zealand",
"regions" : [ { "region" : "Waikato", "size" : 1004 },
{ "region" : "Waikato", "size" : 145 }, { "region" : "Otago", "size" : 1068 } ] }
In document regions array is dynamic in nature. In above document I need to update an increment field size value of ~Waikato`. Instead of putting an another record in array of regions.
My code
BasicDBObject query = new BasicDBObject();
query.put("country", "New Zealand");
query.put("regions.$.region", "Waikato");
BasicDBObject data = new BasicDBObject().append("$inc", new BasicDBObject().append("regions.$.size", 145));
BasicDBObject command = new BasicDBObject();
command.put("$set", data);
collection.update(query, command, true, false);
I need output like these:
{ "_id" : ObjectId("55e7d2a72f68907c17cfcb2f"), "country" : "New Zealand", "regions" : [ { "region" : "Waikato", "size" : 1149 }, { "region" : "Otago", "size" : 1068 } ] }
Please suggest me on these issue.
Your positional $ operator only belongs in the "update portion and not the query. Also you need to .append() in the query otherwise you overwrite:
BasicDBObject query = new BasicDBObject();
query.put("country", "New Zealand");
query.append("regions.region", "Waikato");
BasicDBObject update = new BasicDBObject()
.append("$inc", new BasicDBObject().append("regions.$.size", 145));
collection.update(query, update, true, false);
Basically looks like this ( shell wise ) :
collection.update(
{ "country": "New Zealand", "regions.region": " "Waikato" },
{ "$inc": regions.$.size": 145 },
true,
false
)

MongoDB Query in Array of Arrays and add if not present

I have
{
"Districts" :
[{ "name" : "Krishna"
, "Locations" : [{ "name" : "Vijayawada"}
,{ "name" : "Machilipatnam"}]}
, { "name" : "Guntur"
, "Locations" : [{ "name" : "Satenpalli"}]}
]
, "_id" : 1
, "name" : "Andhra Pradesh"
}
I am trying to create one more Location "Achampet" if District name is "Guntur" so the result should be this below. The result should be the same even if I try to add Achampet more than once.
{
"Districts" :
[{ "name" : "Krishna"
, "Locations" : [{ "name" : "Vijayawada"}
,{ "name" : "Machilipatnam"}]}
, { "name" : "Guntur"
, "Locations" : [{ "name" : "Satenpalli"}
,{ "name" : "Achampet"}]}
]
, "_id" : 1
, "name" : "Andhra Pradesh"
}
But my java code doesn't work
DBObject newLoc = new BasicDBObject("Districts", new BasicDBObject("name", distName).append("Locations", new BasicDBObject("name", locName)));
if (statesColl.findOne(newLoc) == null) {
DBObject updateLoc = new BasicDBObject("$push", newLoc);
statesColl.update(queryDist, updateLoc);
}
It is creating a new District everytime I try to add a location. How can I fix this?
This is how you can do it using the $ positional operator in Java:
...
DBObject selectQuery = new BasicDBObject("_id", 1); // Matches the document
selectQuery.append("Districts.name", distName); // Matches the element in the array where District name = Guntur
BasicDBObject updateFields = new BasicDBObject();
updateFields.put("Districts.$.Locations", new BasicDBObject("name":"Achampet"));
DBObject updateQuery = new BasicDBObject("$addToSet", updateFields);
statesColl.update(selectQuery, updateQuery);
...

Updating inner doc from mongo

This is my sample doc.
{
"_id" : ObjectId("51f20148a85e39af87510305"),
"group_name" : "sai",
"privileges" : [
"Notification",
"News Letter"
],
"users" : [
{
"full_name" : "sumit",
"user_name" : "sumitdesh",
"password" : "magicmoments",
"status" : "Active"
},
{
"full_name" : "ad",
"user_name" : "asd",
"password" : "asdf",
"status" : "Active"
}
]
}
I want to replace inner doc from users array with a new doc.
This is my java code:
BasicDBObject g1=new BasicDBObject();
g1.put("full_name", "ram");
g1.put("user_name", "ram123");
g1.put("password", "pass$123");
g1.put("status", "Inactive");
BasicDBObject doc=new BasicDBObject();
doc.put("users",g1);
BasicDBObject q=new BasicDBObject("users.user_name","asd");
con.update(q,doc);
Any help is appreciated
Expected output is as follows
I want to replace inner doc with these values
{
"_id" : ObjectId("51f20148a85e39af87510305"),
"group_name" : "sai",
"privileges" : [
"Notification",
"News Letter"
],
"users" : [
{
"full_name" : "sumit",
"user_name" : "sumitdesh",
"password" : "magicmoments",
"status" : "Active"
},
{
"full_name" : "ram",
"user_name" : "ram123",
"password" : "pass$123",
"status" : "Inactive"
}
]
}
I must combine $set and $ operators, then you can update an specific item of array.
BasicDBObject g1 = new BasicDBObject();
g1.put("users.$.full_name", "ram");
g1.put("users.$.user_name", "ram123");
g1.put("users.$.password", "pass$123");
g1.put("users.$.status", "Inactive");
BasicDBObject doc = new BasicDBObject();
doc.put("$set", g1);
BasicDBObject q = new BasicDBObject("users.user_name","asd");
con.update(q,doc);
Your code will create a new document consisting only of the new user. To add a new element to an array in an existing document, use the $push operator
BasicDBObject where = new BasicDBObject("_id", new ObjectId("51f20148a85e39af87510305");
BasicDBObject doc = //... your new user object
BasicDBObject push = new BasicDBObject("$push", doc);
con.update(where, push);
To modify a field of an existing document, you can use the set-operator combined with the $-placeholder. This changes the user_name from "foo" to "bar"
BasicDBObject where = new BasicDBObject("users.user_name", "foo");
BasicDBObject value = new BasicDBObject("users.$.user_name", "bar");
BasicDBObject set = new BasicDBObject("$set", value);
con.update(where, set);
But the least headache-inducing way is to just keep the whole DBObject around when you retrieve an object from the database, mirror all modifications in the DBObject, and then call
con.save(dbObject);
An ORM wrapper library can do this for you. But while it is the easiest way, it isn't the most efficient way, because the whole document will be sent to the database. This is a problem which can be easily filed under "premature optimization" when writes are infrequent and the documents are small, but when you save often and have huge documents, it can become an issue.
This is actually fairly simple, if you follow the documentation.
The first difficulty is finding the document to update. You're looking for the user whose user_name field is 'asd', which is done, rather neatly, through the following query:
{'users.user_name': 'asd'}
The field name needs to be escaped in the mongo shell (it's a compound name) but you need not worry about that in Java.
Now that you've found your user, you need to change it. MongoDB magically stores the matched array index as $, which allows you to write the update criteria as:
{
$set: {
'users.$': {
full_name: 'ram',
user_name: 'ram123',
password: 'pass$123',
status: 'inactive'
}
}
}
You obviously know your way around the Java connector, I'll leave the transformation of my JSON object to instances of BasicDBObject to you.

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