Trying to update a document using MongoDB Java Driver - java

Thank you
I just want to thank you for clicking on this question! I've tried my best to make this as thorough as possible.
but still, feel free to let me know if you need to clarify anything further!
if you think the question is too long. you can just read the third & fourth part and post your own solution down here!
Setup
Mongodb Java driver: org.mongodb:mongo-java-driver:3.11.0-rc0
What I want to do
find a specific document with a specific "name" field.
then update the other field or the whole document.
Example Document
// the document that I am trying to find in db
{
"_id":"5de6af7cfa42833bd9849477",
"name":"Richard Koba",
"skills":[]
}
// the document that I have
{
"name":"Richard Koba",
"skills":[jump, dance, sing]
}
// final result in db
{
"_id":"5de6af7cfa42833bd9849477",
"name":"Richard Koba",
"skills":[jump, dance, sing]
}
What I am doing now
// finding a document with same "name" field as input doc and update it with doc
public MongoCollection updateDocument(Document doc, String colName) {
MongoCollection collection;
// make sure collection exist
try {
collection = connectCollection(colName); // returns MongoCollection Obj
} catch (CollectionNotFoundException e) {
MessageHandler.errorMessage(e.getMessage());
return null;
}
// trying to find the document.
if (collection.find(eq("name", doc.get("name"))).first() == null) {
// if document not found, insert a new one
collection.insertOne(doc);
} else {
// if the document found, replace/update it with the one I have
collection.replaceOne(eq("name", doc.get("name")), doc);
}
return collection;
}
What I found about my false solution
collection.find(eq("name", doc.get("name"))).first() never returns null.
Java only tells me it returns an Object. MongoDB Documentation tells me it is a TResult, which point back to MongoIterable<TResult>. I am stuck here.
the code outcome is that none of the documents is inserted/updated in the end.
Reference
https://mongodb.github.io/mongo-java-driver/3.11/javadoc/com/mongodb/client/MongoIterable.html#first()

I tried some code and this works fine. This is not much different from your code.
Created a document from mongo shell:
MongoDB Enterprise > db.users.findOne()
{
"_id" : "5de6af7cfa42833bd9849477",
"name" : "Richard Koba",
"skills" : [ ]
}
My Java Code:
// Test input documents
private Document doc1 = new Document()
.append("name", "Richard Koba")
.append("skills", Arrays.asList("jump", "dance", "sing"));
private Document doc2 = new Document()
.append("name", "Richard K")
.append("skills", Arrays.asList("sings"));
When doc1 is passed to the following method the result is: "### Doc FOUND". And, with doc2 the result is "### Doc NOT found".
private void checkDocument(Document doc) {
MongoClient mongoClient = MongoClients.create("mongodb://localhost/");
MongoDatabase database = mongoClient.getDatabase("javadb");
MongoCollection<Document> collection = database.getCollection("users");
if (collection.find(eq("name", doc.get("name"))).first() == null) {
System.out.println("### Doc NOT found");
}
else {
System.out.println("### Doc FOUND");
}
}
I also tried this, with the same results.
Document d = collection.find(eq("name", doc.get("name"))).first();
if (d == null) { // ... }
I also tried this; works fine too.
if (collection.find(queryFilter).iterator().tryNext() == null) { // ... }
I think there might be some other issue with your code or the database / collection. Some debugging and testing with new data might reveal the real issue.
Did you check if the document already exists in the collection, from mongo shell or Compass tools?
Are you using the right database and collection names?
After each test run are you verifying the data in the database if it is updated / inserted?
collection.find(eq("name", doc.get("name"))).first() never returns
null.
With the code I posted above, the find query did return null when the users collection was empty.

collection.find() return an array of documents. What you actually want here is collection.findOneAndUpdate()
After you get a TDoucment object from findOneAndUpdate, you can use a ObjectMapper e.g.jackson to map it back to a java object

Related

Cannot insert document into collection

I have the following method :
MongoCollection<Document> collection;
...
Document query = new Document();
query.put("uuid", uuid);
query.put("gems", "$exists");
Document document = collection.find(query).first();
if(document == null) {
System.out.println("Not found");
document = new Document();
document.put("uuid", uuid);
document.put("gems", 0L);
collection.insertOne(document);
}
Now, the collection is there, I checked in Mongo, but for some reason the document is never inserted.
I run:
db.(collection).find()
And get no output.
The document is never found, I don't know if my query is correct, but the document is never inserted. This is done with a clean install of MongoDB running on localhost. MongoDB shows as connected and no errors are thrown.
Am I missing something?
This code seems to work, it fixes the insert and finding method:
Document document = collection.find(Filters.eq("uuid", uuid)).first();
if (document == null) {
document = new Document("uuid", uuid);
document.put("gems", 0L);
collection.insertOne(document);
}

Changefeed on one column RethinkDB

I want to have a changefeed on one attribute of my object in rethinkdb in the java language.
I tried this:
Cursor curs = r.db("mytestdb").
table("tennis").
get(Constants.WORKING_PROJECT_ID).
getField("time").
changes().
run(conn);
for (Object doc : curs) {
System.out.println(doc);
}
but I get this com.rethinkdb.gen.exc.ReqlQueryLogicError: Cannot convert STRING to SEQUENCE as an Exception.
Im really new to rethinkDB. Can someone help me ?
getField("time") gets particular field value, you can't subscribe on value.
That's what this com.rethinkdb.gen.exc.ReqlQueryLogicError: Cannot convert STRING to SEQUENCE says.
You can filter changes you want to get:
Cursor curs = r.db("mytestdb").
table("tennis").get(Constants.WORKING_PROJECT_ID)
.filter(row -> row.g("new_val").g("time").ne(row.g("old_val").g("time")))
.changes().run(conn);
for (Object doc : curs) {
}

Cannot find sub-field

I have this data on my mongodb database:
{
"_id" : BinData(3, "bU0bX4VEAMnW7AJ28wXcoA=="),
"online" : false,
"money" : 0,
"rank" : "USER",
"ban" : {
"end" : NumberLong("3027259780628"),
"reason" : "hello"
}
}
and I use this code to access to the ban.end sub-field saved in it:
final Document doc = collcetion.find(new Document("_id", myId)).
projection(Projections.include("ban.end"));
System.out.println(doc); // here is all ok.
// It print out the _id with the
// ban and the end values.
final long a = doc.getLong("ban.end"); // nullptr exception because
// I tryied to do this:
long a = (Long) null;
Is there any way to fix the null pointer reported above? I think I failed something with mongodb, I'm not sure in using ban.end as field name.
I already tried to get, for example, the money value and it works.
getLong returns a Long, not a long. See http://api.mongodb.org/java/current/org/bson/Document.html#getLong-java.lang.Object-.
In other words, you're getting the nullpointer because you're implicitly unboxing it. Just use
final long a = doc.getLong("ban.end");
instead, the handle the null case separately.
I'm not sure in using "ban.end" as field name.
Sadly, you are. You need to get the ban objcect first, before you could access its end attribute.
The logic remains the same for whatever versions.
code in 3.0.4 version of the java driver,
DBCursor docs = collection.find(new BasicDBObject("_id", myId),
new BasicDBObject("ban.end", 1));
while (docs.hasNext())
{
BasicDBObject banObj = (BasicDBObject) docs.next().get("ban");
long end = banObj.getLong("end");
System.out.println(end);
}

How do i do a Save operation on a MongoDB collection using the Java driver?

I just switch over from Python, and need to continue my work with a MongoDB database. One particular task is to save an incoming document (in this case, a tweet) into a collection for archiving. A tweet could comes in multiple times, so I prefer to use save() over insert() since the former do not raise an error if the document already exists in the collection. But it seems the Java driver for MongoDB does not support the save operation. Am I missing something?
EDIT: for reference, i'm using this library 'org.mongodb:mongodb-driver:3.0.2'
Example code:
MongoCollection<Document> tweets = db.getCollection("tweets");
...
Document tweet = (Document) currentDocument.get("tweet");
tweets.insertOne(tweet);
The last line raise this error when the tweet already exists:
Exception in thread "main" com.mongodb.MongoWriteException: insertDocument :: caused by :: 11000 E11000 duplicate key error index: db.tweets.$_id_ dup key: { : ObjectId('55a403b87f030345e84747eb') }
Using the 3.x MongoDB Java driver you can use MongoCollection#replaceOne(Document, Document, UpdateOptions) like this:
MongoClient mongoClient = ...
MongoDatabase database = mongoClient.getDatabase("myDB");
MongoCollection<Document> tweets = db.getCollection("tweets");
...
Document tweet = (Document) currentDocument.get("tweet");
tweets.replaceOne(tweet, tweet, new UpdateOptions().upsert(true));
This will avoid the duplicate key error. However, this is not exactly the same as using DBCollection#save(DBObject), since it uses the whole Document as filter instead of just the _id field. To mirror the old save method, you would have to write something like this:
public static void save(MongoCollection<Document> collection, Document document) {
Object id = document.get("_id");
if (id == null) {
collection.insertOne(document);
} else {
collection.replaceOne(eq("_id", id), document, new UpdateOptions().upsert(true));
}
}

Java MongoDB getting value for sub document

I am trying to get the value of a key from a sub-document and I can't seem to figure out how to use the BasicDBObject.get() function since the key is embedded two levels deep. Here is the structure of the document
File {
name: file_1
report: {
name: report_1,
group: RnD
}
}
Basically a file has multiple reports and I need to retrieve the names of all reports in a given file. I am able to do BasicDBObject.get("name") and I can get the value "file_1", but how do I do something like this BasicDBObject.get("report.name")? I tried that but it did not work.
You should first get the "report" object and then access its contents.You can see the sample code in the below.
DBCursor cur = coll.find();
for (DBObject doc : cur) {
String fileName = (String) doc.get("name");
System.out.println(fileName);
DBObject report = (BasicDBObject) doc.get("report");
String reportName = (String) report.get("name");
System.out.println(reportName);
}
I found a second way of doing it, on another post (didnt save the link otherwise I would have included that).
(BasicDBObject)(query.get("report")).getString("name")
where query = (BasicDBObject) cursor.next()
You can also use queries, as in the case of MongoTemplate and so on...
Query query = new Query(Criteria.where("report.name").is("some value"));
You can try this, this worked for me
BasicDBObject query = new BasicDBObject("report.name", "some value");

Categories