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.
Related
I recently switched from java mongo driver 3.1 to 3.4 in attempts to use Cosmo db api for mongo on azure. I am having issues with the driver when attempting to modify and field within an array.
My mongo Object looks like so
{
"_id" : ObjectId("5af4d4e97bad4700076d7aea"),
"URI" : "v3egoun#myip"
},
"record" : false,
"active" : true,
"audioonly" : true,
"environment" : "dev",
"participants" : [
{
"user" : "test1.medocity#test.org",
"state" : "pending",
"callid" : "null",
"host" : true
},
{
"user" : "test2.medocity#test.org",
"state" : "pending",
"callid" : "74ff79f83c375355058838a1b8d0ec03#test.org",
"host" : false
}
]
}
I wish to modify the variables for state and callid within the array for the user matching the query:
BasicDBObject query = new BasicDBObject();
query.put("URI", URI);
query.put("participants.user", FROMURI);
BasicDBObject data = new BasicDBObject();
data.put("participants.$.state", newstate.toString());
data.put("participants.$.callid", XMScallid);
BasicDBObject command = new BasicDBObject();
command.put("$set", data);
table.updateOne(query, command);
As of now I get the following error.
Exception in thread "Thread-13" com.mongodb.MongoWriteException: Invalid BSON field name 'participants.$.state'
Anyone have an Idea of how I can modify the state within the participants array for the user provided in the query?
Thanks
I am new to mongodb.I am trying to match username and password in collection array. My sample doc is
{
"_id" : ObjectId("51f20148a85e39af87510305"),
"group_name" : "sai",
"users" : [
{
"full_name" : "sumit",
"user_name" : "sumitdesh",
"password" : "mggg",
"status" : "Active"
},
{
"full_name" : "ad",
"user_name" : "asd",
"password" : "asdf",
"status" : "Active"
},
}
I am trying to match user name and password enter by user in above array.If user name and password match with our data,user will get login. My java code is
BasicDBObject u = new BasicDBObject("users.user_name", uname);
BasicDBObject p = new BasicDBObject("users.password", password);
f=con.coll.find(u,p);
Your document structure might get in the way here. How do you distinguish the user logging in? If you get a match, it will return the whole document, with all users.
Anyhow, to query with multiple comparisons:
BasicDBObject query = new BasicDBObject();
List<BasicDBObject> parts = new ArrayList<BasicDBObject>();
parts.add(new BasicDBObject("users.user_name", uname));
parts.add(new BasicDBObject("users.password", password));
query.put("$and", parts);
DBCursor cursor = collection.find(query);
while (cursor.hasNext()) {
System.out.println(cursor.next());
}
You need to use the $elemMatch query operator.
Something like this should work:
BasicDBObject elementQuery = new BasicDBObject("user_name", uname);
element.put("password", password);
BasicDBObject query = new BasicDBObject("users",
new BasicDBObject("$elemMatch", elementQuery);
f=con.coll.find(query);
Rob.
P.S. On a side note - having all of the users in a single document is probably not optimal. Have you considered having a separate document for each user with the user name and password?
An example of a schema that might perform better is to divide the groups and users into two collections. Each user will have a document like:
{
"_id" : "sumitdesh",
"full_name" : "sumit",
"password" : "mggg",
"status" : "Active"
"groups" : [ "sai", "admin" ],
}
You will probably want to index the 'groups' if you query for all of the members of a group often.
The groups document will then look like:
{
"_id" : "sai",
"permissions" : [ "read", "write_secrets" ]
}
Index permissions.
A check for read permission for the sumitdesh user is then:
db.groups.findOne(
{
_id : { "$in" : [ "sai", "admin" ] } ,
"permissions" : "read"
}
);
Note that the array for the '$in' same as the array of groups from 'sumitdesh' user document.
P.P.S. ...and when you say password you mean a hash (SHA-2?) of the salted password? Right?
My sample doc is
{
"_id" : ObjectId("51f89c1484ae3aa758ad56e9"),
"group_name" : "Operator",
"privileges" : [
"Add Group",
"Edit/Delete Group",
"Add User",
"Edit/Delete User",
"Log History",
"Add Stopwords Group",
"Edit/Delete Stopwords Group",
"Add Stopwords",
"Edit/Delete Stopwords",
"Recomended Stopwords"
],
"users" : [
{
"full_name" : "operator1",
"user_name" : "operator",
"password" : "pass$123",
"status" : "Active"
},
{
"full_name" : "Sumit Dshpande",
"user_name" : "dsumit",
"password" : "pass$123",
"status" : "Active"
}
]
}
I am trying to match user_name and password in users array entered by user.
My java code is :
BasicDBObject query = new BasicDBObject();
List<BasicDBObject> parts = new ArrayList<BasicDBObject>();
parts.add(new BasicDBObject("users.user_name", uname));
parts.add(new BasicDBObject("users.password", password));
query.put("$and", parts);
DBCursor cursor = collection.find(query);
while (cursor.hasNext()) {
System.out.println(cursor.next());
}
But it returns all users in matching array.I want users under group so that I can change group privileges.
Is this right approach for schema designing in nosql.
We would need to get holistic information about your application in order to tell you if you're making the right modeling decisions; however, I can help you with your current query.
In order to match multiple attributes within the same element of an array, you should use the $elemMatch operator (http://docs.mongodb.org/manual/reference/projection/elemMatch/).
eg)
collection.find({users:{$elemMatch:{username:uname,password:password}}});
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
}
I'm using Java Mongo DB driver.
Im doing some OR and AND operation to query the collection.
QueryObj = new BasicDBObject("key1",Pattern.compile("v",Pattern.CASE_INSENSITIVE));
QueryList.add(QueryObj);
DBObject OrQuery = new BasicDBObject("$or", QueryList);
DBCursor cursor = MyCollection.find(OrQuery);
my Sample collection have 4 rows(JSON format might be wrong)
{
"key1": ["val1","val3"]
},
{
"key1": ["val2","val3"]
},
{
"key1": ["val3"]
},
{
"key1": ["val1","val2"]
}
If i search for "val2"
QueryObj = new BasicDBObject("key1",Pattern.compile("val2",Pattern.CASE_INSENSITIVE));
i'm getting expected output 2nd and 4th row
{
"key1": ["val2","val3"]
},
{
"key1": ["val1","val2"]
}
if i search just "v"
QueryObj = new BasicDBObject("key1",Pattern.compile("v",Pattern.CASE_INSENSITIVE));
i should get null set, but getting all the 4 rows, though the array have a character "v".
i need to search the whole word.
Do you mean that you want to search for the complete word 'v' -- in which case, I believe your pattern would be as follows where ^ denote the start of word and $ denote the end of word.
QueryObj = new BasicDBObject("key1",Pattern.compile("^v$",Pattern.CASE_INSENSITIVE));
Regards,
Kay
I hope it should help you
values ="val1";
CMD we use in DB as :
db.collection_name.findOne({ key1: "val1"})
Likewise use
query.put("key1", values)
Use the findOne() instead of find() in the statement
Correct me if 'm wrong
If you have the 4 documents above you can just use the following query to retrieve only the ones you need:
db.collection.find({"key1": "val2"})
This returns:
{ "_id" : ObjectId("507587fdf1ab6b3d9e0151d3"), "key1" : [ "val2", "val3" ] }
{ "_id" : ObjectId("50758801f1ab6b3d9e0151d5"), "key1" : [ "val1", "val2" ] }
(assuming your collection is called 'collection').
In the Java Driver the correct call should be:
Mongo mongo = new Mongo("localhost", 27017);
DB db = mongo.getDB("test");
BasicDBObject query = new BasicDBObject("key1", "val2");
db.getCollection("collection").find(query);
//omitting try catch
If I understand your question correct, you don't need to use a Pattern here.
hope this helps