why java mongodb driver update a value can't start with $ - java

UpdateOptions options = new UpdateOptions().upsert(true);
Bson filters = Filters.eq("id", 123456);
List<Bson> bsonArrayList = new ArrayList<>();
bsonArrayList.add(Updates.set("income", "$300k"));
UpdateResult updateResult = mongoExe.updateOne(filters, bsonArrayList, options);
The field name is income, value is $200k. It can't update until I delete the $
bsonArrayList.add(Updates.set("income", "300k"));
how can I do to make it ?
why java mongodb driver update a value can't start with $?

You can use literal:
import static com.mongodb.client.model.Filters.eq;
...
bsonArrayList.add(Updates.set("income", eq("$literal", "$300k")));
or
bsonArrayList.add(Updates.set("income", new Document("$literal", "$300k")));
eq is just a container (or shorthand for Document) in this case.

The $ is a special character in MongoDB, see here for a description.
You can fix it by escaping the character, see here for how.

Related

How can I retrieve DBObjects that contains a substring of a search-word?

I am using MongoDB with Java Driver (http://tinyurl.com/dyjxz8k). In my application I want it to be possible to give results that contains a substring of the users search-term. The method looks like this:
*searchlabel = the name of a field
*searchTerm = the users searchword
private void dbSearch(String searchlabel, String searchTerm){
if(searchTerm != null && (searchTerm.length() > 0)){
DBCollection coll = db.getCollection("MediaCollection");
BasicDBObject query = new BasicDBObject(searchlabel, searchTerm);
DBCursor cursor = coll.find();
cursor = coll.find(query);
try {
while(cursor.hasNext()) {
System.out.println(cursor.next());
//view.showResult(cursor.next());
}
} finally {
cursor.close();
}
}
}
Does anybody have any idea about how I can solve this? Thanks in advance =) And a small additional question: How can I handle the DBObjects according to presentation in (a JLabel in) view?
For text-searching in Mongo, there are two options:
$regex operator - however unless you have a simple prefix regexp, queries won't use an index, and will result in a full scan, which usually is slow
In Mongo 2.4, a new text index has been introduced. A text query will split your query into words, and do an or-search for documents including any of the words. Text indexes also eliminate some stop-words and have simple stemming for some languages (see the docs).
If you are looking for a more advanced full-text search engine, with more powerful tokenising, stemming, autocomplete etc., maybe a better fit would be e.g. ElasticSearch.
I use this method in the mongo console to search with a regular expression in JavaScript:
// My name to search for
var searchWord = "alex";
// Construct a query with a simple /^alex$/i regex
var query = {};
query.animalName = new RegExp("^"+searchWord+"$","i");
// Perform find operation
var lionsNamedAlex = db.lions.find(query);

MongoDB Java Driver - Use exists projection in find query

I want to get all documents where the field download does not exists
find{ "download" : {$exists: false}}
For Java I found an Example:
BasicDBObject neQuery = new BasicDBObject();
neQuery.put("number", new BasicDBObject("$ne", 4));
DBCursor cursor = collection.find(neQuery);
while(cursor.hasNext()) {
System.out.println(cursor.next());
}
My Adaption is
BasicDBObject field = new BasicDBObject();
field.put("entities.media", 1);
field.put("download", new BasicDBObject("$exists",false));
System.out.println("Start Find");
DBCursor cursor = collection.find(query,field);
System.out.println("End Find Start Loop ALL 100k");
int i = 1;
while(cursor.hasNext())
The Exists Line is not working:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused by: com.mongodb.MongoException: Unsupported projection option: $exists
at com.mongodb.MongoException.parse(MongoException.java:82)
at com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:314)
at com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:295)
at com.mongodb.DBCursor._check(DBCursor.java:368)
at com.mongodb.DBCursor._hasNext(DBCursor.java:459)
at com.mongodb.DBCursor.hasNext(DBCursor.java:484)
at ImgToDisk.main(ImgToDisk.java:61)
... 5 more
It have no clue right now which the right adaption would be, since I got my query working in the shell and with UMongo, the transfer to java seems to be not so easy to see.
you use
collection.find(query,field);
the DBObject that is the 2nd parameter to the find method is used to indicate which attributes of the resulting documents you want to be returned. It is useful for reducing network load.
In your example, you try to put an $exists clause into the field DBObject. That won't work.
The 2nd parameter object can only have attribute values of 1(include this attribute) or 0(exclude).
Put it into the first DBObject called query instead.
Also see here and here
you can use DBCollection to do that with JAVA API
public List<BasicDBObject> Query(String collection, Map<String, String> query, String... excludes) {
BasicDBObject bquery = new BasicDBObject(query);
BasicDBObject bexcludes = new BasicDBObject(excludes.length);
for (String ex : excludes) {
bexcludes.append(ex, false);
}
return db.getCollection(collection, BasicDBObject.class).find(bquery).projection(bexcludes)
.into(new ArrayList<BasicDBObject>());
}
db is MongoDataBase
We need to specify two things.
First :
collection.find(query,field);
The above command is not from MongoDB Java driver.
That means we can run only in the mongo shell (or in the mongo Compass) and not in the java.
Second:
to limit the fields in java you can use projection() like the following code
find(queryFilter)
.projection(fields(include("title", "year"),exclude("_id")))
Complete Example:
Bson queryFilter = eq("cast", "Salma Hayek");
//or Document queryFilter = new Document("cast", "Salma Hayek");
Document result =
collection
.find(queryFilter)
//.limit(1) if you want to limit the result
.projection(fields(include("title", "year"),exclude("_id")))
//or .projection(fields(include("title", "year"), excludeId()))
//or .projection(new Document("title", 1).append("year", 1))
.iterator()
.tryNext();

Remove and Add new array into the JSON object using MongoDB

I have JSON object :
{ "_id" : "1", "_class" : "com.model.Test", "projectList" : [ {
"projectID" : "Spring", "resourceIDList" : [ "Mark","David" ] },
{ "projectID" : "MongoDB", "resourceIDList" : [ "Nosa ] }
I need to be able to remove the resourceIDList for Project "Spring" and assign a new ResourceIDList.
The ResourceIDList is just List
Whenever I try to use the following,nothing is updated at DB:
Query query = new Query(where("_id").is("1").and("projectID").is("Spring"));
mongoOperations.updateMulti( query,new Update().set("ressourceIDList", populateResources()), Test.class);
Replacing the resourceIDList in the embedded document matching {"projectList.projectID":"Spring"} may be accomplished in the JavaScript shell like so:
(I like to start with the JS shell, because it is less verbose than Java and the syntax is relatively straightforward. Examples with JS can then be applied to any of the language drivers.)
> db.collection.update({_id:"1", "projectList.projectID":"Spring"}, {$set:{"projectList.$.resourceIDList":["Something", "new"]}})
The documentation on using the "$" operator to modify embedded documents may be found in the "The $ positional operator" section of the "Updating" documentation:
http://www.mongodb.org/display/DOCS/Updating#Updating-The%24positionaloperator
There is more information on embedded documents in the "Dot Notation (Reaching into Objects)" Documentation:
http://www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29
The above may be done in the Java Driver like so:
Mongo m = new Mongo("localhost", 27017);
DB db = m.getDB("test");
DBCollection myColl = db.getCollection("collection");
ArrayList<String> newResourceIDList = new ArrayList<String>();
newResourceIDList.add("Something");
newResourceIDList.add("new");
BasicDBObject myQuery = new BasicDBObject("_id", "1");
myQuery.put("projectList.projectID", "Spring");
BasicDBObject myUpdate = new BasicDBObject("$set", new BasicDBObject("projectList.$.resourceIDList", newResourceIDList));
myColl.update(myQuery, myUpdate);
System.out.println(myColl.findOne().toString());
If you have multiple documents that match {"projectList.projectID" : "Spring"} you can update them at once using the multi = true option. With the Java driver it would look like this:
myColl.update(myQuery, myUpdate, false, true);
In the above, "false" represents "upsert = false", and "true" represents "multi = true". This is explained in the documentation on the "Update" command:
http://www.mongodb.org/display/DOCS/Updating#Updating-update%28%29
Unfortunately, I am not familiar with the Spring framework, so I am unable to tell you how to do this with the "mongoOperations" class. Hopefully, the above will improve your understanding on how embedded documents may be updated in Mongo, and you will be able to accomplish what you need to do with Spring.

$push and $set in same MongoDB update

I'm trying to use MongoDB's Java driver to make two updates ($set and $push) to a record in the same operation. I'm using code similar to the following:
BasicDBObject pushUpdate = new BasicDBObject().append("$push", new BasicDBObject().append("values", dboVital));
BasicDBObject setUpdate = new BasicDBObject().append("$set", new BasicDBObject().append("endTime", time));
BasicDBList combinedUpdate = new BasicDBList();
combinedUpdate.add( pushUpdate);
combinedUpdate.add( setUpdate);
collection.update( new BasicDBObject().append("_id", pageId), combinedUpdate, true, false);
When I combine the $set and $push into the same update via a BasicDBList, I get an IllegalArgumentException: "fields stored in the db can't start with '$' (Bad Key: '$push')".
If I make two separate updates, both pushUpdate and setUpdate produce valid results.
Thanks!
I don't know Java driver, but do you have to create a list there? What happens if you try this code?
BasicDBObject update = new BasicDBObject().append("$push", new BasicDBObject().append("values", dboVital));
update = update.append("$set", new BasicDBObject().append("endTime", time));
collection.update( new BasicDBObject().append("_id", pageId), update, true, false);
This should produce the equivalent of
db.collection.update({_id: pageId}, {$push: {values: dboVital}, $set: {endTime: time}});
Whereas your code produces (I suspect) this:
db.collection.update({_id: pageId}, [{$push: {values: dboVital}}, {$set: {endTime: time}}]);
BasicDBObject update = new BasicDBObject().append("$push", new BasicDBObject().append("values", dboVital));
update = update.append("$set", new BasicDBObject().append("endTime", time));
collection.update( new BasicDBObject().append("_id", pageId), update, true, false);
My mongodb version is 3.4.20 and while using
db.collection.update({_id: pageId}, [{$push: {values: dboVital}}, {$set: {endTime: time}}]);
I received error
[thread1] Error: field names cannot start with $ [$push] :
To solve that error we can use:
db.collection.update({_id: pageId}, {$push: {values: dboVital}, $set: {endTime: time}});

How to query mongodb with “like” using the java api?

this question is very similar to another post
I basically want to use the mongodb version of the sql "like" '%m%' operator
but in my situation i'm using the java api for mongodb, while the other post is using mongodb shell
i tried what was posted in the other thread and it worked fine
db.users.find({"name": /m/})
but in java, i'm using the put method on the BasicDBObject and passing it into the find() method on a DBCollections object
BasicDBObject q = new BasicDBOBject();
q.put("name", "/"+m+"/");
dbc.find(q);
but this doesn't seem to be working.
anyone has any ideas?
You need to pass an instance of a Java RegEx (java.util.regex.Pattern):
BasicDBObject q = new BasicDBObject();
q.put("name", java.util.regex.Pattern.compile(m));
dbc.find(q);
This will be converted to a MongoDB regex when sent to the server, as well as any RegEx flags.
You must first quote your text and then use the compile to get a regex expression:
q.put("name", Pattern.compile(Pattern.quote(m)));
Without using java.util.Pattern.quote() some characters are not escaped.
e.g. using ? as the m parameter will throw an exception.
To make it case insensitive:
Document doc = new Document("name", Pattern.compile(keyword, Pattern.CASE_INSENSITIVE));
collection.find(doc);
In spring data mongodb, this can be done as:
Query query = new Query();
query.limit(10);
query.addCriteria(Criteria.where("tagName").regex(tagName));
mongoOperation.find(query, Tags.class);
Document doc = new Document("name", Pattern.compile(keyword));
collection.find(doc);
Might not be the actual answer, ( Executing the terminal query directly )
public void displayDetails() {
try {
// DB db = roleDao.returnDB();
MongoClient mongoClient = new MongoClient("localhost", 5000);
DB db = mongoClient.getDB("test");
db.eval("db.test.update({'id':{'$not':{'$in':[/su/]}}},{$set:{'test':'test3'}},true,true)", new Object[] {});
System.out.println("inserted ");
} catch (Exception e) {
System.out.println(e);
}
}
if(searchType.equals("employeeId"))
{
query.addCriteria(Criteria.where(searchType).regex(java.util.regex.Pattern.compile(searchValue)));
employees = mongoOperations.find(query, Employee.class, "OfficialInformation");
}

Categories

Resources