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
Related
I have the following mongoDB object
{
"_id" : ObjectId("5c3f32a4e17c5739bccb9115"),
"name" : "John",
"friends" : [
{
"name" : "Paul"
},
{
"name" : "Lisa"
}
]
}
I need to delete some element from it. In native mongodb query it looks like
db.users.update({}, {$pull: {friends: {name:"Lisa"}}})
But how can I do this via Morhia API?
I resolve this issue by using:
Query<Group> query = getDatastore().createQuery(Group.class);
UpdateOperations<Group> ops = getDatastore().createUpdateOperations(Group.class)
.removeAll("friends", new BasicDBObject("name", "Lisa"));
getDatastore().update(query, ops);
I have the following document in MongoDb collection called hosts
{ "_id" : ObjectId("532aeec040a83df82181ff3c"),
"os" : "WINDOWS",
"name" : "Host 1",
"bas" : [
{ "wwn" : "EE:00:11:FF", "id" : "1" },
{ "wwn" : "AA:00:11:BB", "id" : "2" } ]
}
Now I want to update ba of id=1 in Host of name=Host 1 to { "wwn" : "AA:BB:CC:DD", "id" : "11" }. After the update the result will be
{ "_id" : ObjectId("532aeec040a83df82181ff3c"),
"os" : "WINDOWS",
"name" : "Host 1",
"bas" : [
{ "wwn" : "AA:BB:CC:DD", "id" : "11" },
{ "wwn" : "AA:00:11:BB", "id" : "2" } ]
}
For this I used the mongo shell command
db.hosts.update( { name : "Host 1", "bas.id" : "1" },
{ "$set" : { "bas.$" : { wwn : "AA:BB:CC:DD", id : "11"} }} );
which worked great. Now I wanted to do the same using Java drivers and here is my code
BasicDBObject example = new BasicDBObject("name", "Host 1").append("bas\uff0eid", "1");
BasicDBObject newValue = new BasicDBObject("\u0024set", new BasicDBObject("bas\uff0e\u0024", new BasicDBObject().append("wwn", "AA:BB:CC:DD).append("id","11")) ;
collection.update(example, newValue);
In the above code I had to replace . with \uff0 and $ with \u0024 to avoid exception being thrown. This update call is not updating the collection. When I inspected the BasicDBObject.toString() the JSON were same as what I had typed on console. Please help me.
I don't understand why you should need to write $ and . as Unicode escapes. I tried running your code with the actual characters in them and it worked fine with the 2.11 Java driver.
But your code has two problems: 1) the full stop . is \u002e, not \uff0e, which is a very different character. 2) the syntax of the last part of the statement is not correct, but that is probably a copying error.
Here's the code that I used, and it worked fine (I only created the objects and didn't actually run it against the database but I don't see why that wouldn't work).
BasicDBObject example = new BasicDBObject("name", "Host 1").append("bas.id", "1");
BasicDBObject newValue = new BasicDBObject("$set",
new BasicDBObject("bas.$",
new BasicDBObject()
.append("wwn", "AA:BB:CC:DD").append("id","11"))) ;
https://github.com/mongodb/mongo-java-driver/blob/master/src/main/com/mongodb/DBCollectionImpl.java#L249
If your value object doesn't have a key starting with $ then it will check the embedded document for illegal characters. Can you post your original code that had this problem, without the escapes?
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.
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?
I have a string as:
'"startDate" : {"\\$gte" : new Date() }'
I actually want to query my mongodb database collection for all the collections with dates after the present date.Here is a sample document:
{
"_id" : ObjectId("51e2a857adc0c2fb535f6904"),
"dateInfo" : {
"dates" : {
"startDate" : ISODate("2013-07-13T04:00:00Z"),
"endDate" : ISODate("2013-07-19T20:00:00Z")
},
"named" : "name1",
"fieldX" : "field1",
"contact" : {
"numbs" : ["+44 121 127 127", "+44 568 789 256", "+44 687 5788 9875"]
}
},
"Locality" : "locality1",
"type" : "ewhet"
}
from mongo shell, I am able to query it as follows:
db.collectionName.find({"dateInfo.dates.startDate" : {"$gte" : new Date()}})
Now I want to do it from groovy. I am trying to do it as(using mongoDB java api):
DBCursor cursor = db.collectionName.find(new JsonSlurper().parseText('{"startDate" : {"\$gte" : new Date() }}'))
Above code gives error as:
Lexing failed on line: 1, column: 48, while reading 'new ', was trying to match the constant 'null'
Now the problem with JsonSlurper is that it requires double quotes in both key and value names.But in case I put a double quote in new Date(), it wont be evaluated by mongodb.
So what can be done here?
Have you tried:
db.collectionName.find( [ 'dateInfo.dates.startDate' : ['$gte' : new Date() ] ] )