I have a Mongo collection like this
email{
"isConfirmed" : true/[or false]
"email" : "xxxxxxxxxxx"
}
When I am trying to update the isConfirmed field to true or false, depending on the email which apparently is unique, it takes ages.
The programming language I am using is Java
Here's my code.
List<String> clientEmails = new ArrayList<String>();
Mongo mongoConnection = new Mongo();
DB mongoDatabase = mongoConnection.getDB(DB_NAME);
DBCollection mongoCollection = mongoDatabase.getCollection(COLLECTION_NAME);
int size = clientEmails.size();
for(int i=0;
i
<
size; i++)
{
BasicDBObject query = new BasicDBObject();
System.out.println(clientEmails.get(i).toString());
query.put("email.email", clientEmails.get(i).toString());
BasicDBObject Update = new BasicDBObject("$set", new BasicDBObject("email.isConfirmed", false));
mongoCollection.update(query, Update);
This one takes ages to run through the collection which consists of around 3500 entries]
//mongoCollection.findAndModify(query, Update);
Even findAndModify doesn't work at all, I am not sure if I am missing something here
However, I have tried with the DBcursor, it works but it takes around 3 minutes to run.
// DBCursor cursor = mongoCollection.find(query);
//
// while(cursor.hasNext()){
// BasicDBObject Update = new BasicDBObject("$set", new BasicDBObject("email.isConfirmed", true));
// mongoCollection.update(cursor.next(), Update);
// }
This method takes around 3 minutes. Can someone suggest me of a workaround or something?
Do you have an index on email.email? If not the query has to do a complete collection scan to find the correct document every time you call update.
You also might want to run mongostat for a while to see what else is going on that could be causing the slowdown. mongostat -h will explain what all the fields mean.
If you were using IDE(like Eclipse) download mongo java driver source as well. Set up breakpoint at
mongoCollection.findAndModify(query, Update);
Step into the java driver, actually you could find excatlly cmd string send to mongo. also actual result from mongo db which should give you more information. Also you can copy/paste cmd string and put into mongo shell, and see what happens next.
I got a issue with findAndModify method, by troubleshooting as I said, found I used wrong 'COLLECTION_NAME' in my code.
I'm using mongo v1.8 and java driver v2.5.3, this method works for me.
Related
I have a Java program that successfully creates a mongo database; after the program runs the code to insert the data, I can use the mongo command line program to view the data.
I am trying to write a little test code that reads that data, finds max values, and the like. But I can't seem to get 'find()' to work. I have the following:
MongoClient readClient = new MongoClient();
DB db = readClient.getDB("x");
DBCollection readings = db.getCollection("y");
DBCursor cursor = readings.find();
DBObject element = cursor.curr();
The database x and the collection y are there, I can see them from the command line program. But if I put a breakpoint after the cursor.curr() statement, the element is null.
The previous version of the code used the same DB and DBCollection objects used to create the database, but thought perhaps that meant there was a cursor positioned after all the records, so I created the new MongoClient on the theory that it would start at the beginning of the collection again. But it isn't working. What am I doing wrong? Is there some 'close()' or 'flush()' or something that need to include?
(corrected to say the element is null, originally stated it was the cursor)
It seems I have to position the cursor an initial time before curr() works; next() does what I want instead.
Running a java spring project (v2) with mongo v4.
Trying to update a nested object and been reading a lot on SO but havent found any good solution.
I have something like the following:
menu {
id
name
categories {
id
name
products {
id
price
referenceProduct {
id
name
}
}
}
}
When I update a reference product, then I want all my referenceproducts in menus to be updated as well.
I have tried the following:
Query query = Query.query(Criteria
.where("menuProductCategories.menuProducts.refProduct.id").is(refProduct.getId())
);
Update update = new Update().set("menuProductCategories.$.menuProducts.$.refProduct", refProduct);
But then I get the too many positional elements found.
Next idea would be to use arrayfilters using something like the following (just trying to update name prop to 'TEST'):
Bson filter = Filters.eq("menuProductCategories.menuProducts.refProduct.id", new ObjectId(refProduct.getId()));
Bson update = new Document("$set", new Document().append("menuProductCategories.$[i].menuProducts.$[j].refProduct.name", "TEST"));
But then I get stuck on how to specify my arrayfilters since they all assume that you know the index, which I don't since I want to do a full search and update all that matches my initial criteria.
Any ideas? Of course I could just retrieve all the menus and iterate over them, but I would love to find a small neat solution.
You can use below query in 3.6 server version with 3.6.x mongodb driver.
MongoCollection<Document> collection = mongoTemplate.getDb().getCollection("col");
Bson update = Updates.set("menuProductCategories.$[].menuProducts.$[i].refProduct.name", "TEST");
Bson filter = Filters.eq("i.refProduct.id", new ObjectId(refProduct.getId()));
UpdateOptions updateOptions = new UpdateOptions().arrayFilters(Arrays.asList(filter));
collection.updateOne(null, update, updateOptions);
I'm having a problem with MongoDB using Java when I try adding documents with customized _id field. And when I insert new document to that collection, I want to ignore the document if it's _id has already existed.
In Mongo shell, collection.save() can be used in this case but I cannot find the equivalent method to work with MongoDB java driver.
Just to add an example:
I have a collection of documents containing websites' information
with the URLs as _id field (which is unique)
I want to add some more documents. In those new documents, some might be existing in the current collection. So I want to keep adding all the new documents except for the duplicate ones.
This can be achieve by collection.save() in Mongo Shell but using MongoDB Java Driver, I can't find the equivalent method.
Hopefully someone can share the solution. Thanks in advance!
In the MongoDB Java driver, you could try using the BulkWriteOperation object with the initializeOrderedBulkOperation() method of the DBCollection object (the one that contains your collection). This is used as follows:
MongoClient mongo = new MongoClient("localhost", port_number);
DB db = mongo.getDB("db_name");
ArrayList<DBObject> objectList; // Fill this list with your objects to insert
BulkWriteOperation operation = col.initializeOrderedBulkOperation();
for (int i = 0; i < objectList.size(); i++) {
operation.insert(objectList.get(i));
}
BulkWriteResult result = operation.execute();
With this method, your documents will be inserted one at a time with error handling on each insert, so documents that have a duplicated id will throw an error as usual, but the operation will still continue with the rest of the documents. In the end, you can use the getInsertedCount() method of the BulkWriteResult object to know how many documents were really inserted.
This can prove to be a bit ineffective if lots of data is inserted this way, though. This is just sample code (that was found on journaldev.com and edited to fit your situation.). You may need to edit it so it fits your current configuration. It is also untested.
I guess save is doing something like this.
fun save(doc: Document, col: MongoCollection<Document>) {
if (doc.getObjectId("_id") != null) {
doc.put("_id", ObjectId()) // generate a new id
}
col.replaceOne(Document("_id", doc.getObjectId("_id")), doc)
}
Maybe they removed save so you decide how to generate the new id.
How do I query in mongoDB using the mongoDB java driver for a numberLong field?
I tried this according to this SO post: Java Mongodb numberlong query but it does not work.
Query query= new Query();
query.addCriteria(Criteria.where("time").is("NumberLong("+article.getDate()+")"));
I also tried this where article.getDate() has a return type of Long and it does not work:
query.addCriteria(Criteria.where("time").is(article.getDate()));
There is no new NumberLong object within the java driver to use.
https://docs.mongodb.org/manual/core/shell-types/ suggest that one uses NumberLong() wrapper but it is only for the javascript shell, not for java.
MongoClient client = new MongoClient();
MongoDatabase mongoDb = client.getDatabase("test");
MongoCollection<Document> mongoCollection = mongoDb
.getCollection("numberFormatTest");
mongoCollection.drop();
Document smith = new Document("name", "Smith").append("age", 30)
.append("profession", "Programmer")
.append("phoneNo", "9848022338");
Document jones = new Document("name", "Jones").append("age", 30)
.append("profession", "Hacker")
.append("phoneNo", "9000000000000");
printJson(smith);
printJson(jones);
// mongoCollection.insertMany(asList(smith,jones));
System.out.println("Phone number: "
+ Long.valueOf(smith.getString("phoneNo")).longValue());
The above piece of code might work for you. At the moment, I tried with find but it will work for updates as well.
Even in the above link shared by you,NumberLong wrapper saves the field value in string datatype not as a long datatype. The below statement proves it.
"The NumberLong() wrapper accepts the long as a string:"
I think it was just my oversight in this case. The query here actually works:
query.addCriteria(Criteria.where("time").is(article.getDate()));
I had called my object field as "date" instead of "time", which met it did not get picked up when i queried. Changing it as follows made it work properly.
query.addCriteria(Criteria.where("date").is(article.getDate()));
I am new to Mongo DB and having trouble as it is behaving differently in different environments ( Dev , QA and Production)
I am using findAndModify to Update the Records in my MongoDB .
There is a Job that runs daily which Updates /Inserts Data to Mongo DB , and i am using findAndModify to Update the Record .
But what i observed is that the first record that is returned by findAndModify is different in Dev , QA and Production environemnts although the three environments are having the same Data ??
As per the Mongo DB document , it states that findAndModify will modify the first document
Currently this is my code :
BasicDBObject update = new BasicDBObject();
update.append("$set", new BasicDBObject(dataformed));
coll.findAndModify(query, update);
Please let me know how can i make sure that , the findAndModify returns the Last Updated Record , rather than depending upon un predictable behaviour ??
Edited Part
I am trying to use sort for my code but it is giving me compilation errors
coll.findAndModify(query, sort: { rating: 1 }, update);
I have a field called as lastUpdated which is created using System.currentTimeMilis
So can i use this lastUpdated as shown this way to get the Last Updated Record
coll.findAndModify( query,
new BasicDBObject("sort", new BasicDBObject("lastUpdated ", -1)),
update);
It appears you are using Java, so you have to construct the sort parameter as a DBObject, just like the other parameters:
coll.findAndModify(
query,
new BasicDBObject("sort", new BasicDBObject("rating", 1)),
update);
As we already explained to you in your other question, you have to add a field to the document which contains the date it was changed and then sort by that field or you have to use a capped collection, because they guarantee that the insertion order is preserved.