[JAVA-2284] The updateOne command with upsert option does not work if document does not exist already. Created: 20/Aug/16  Updated: 11/Sep/19  Resolved: 29/Aug/16

Status: Closed
Project: Java Driver
Component/s: Async
Affects Version/s: 3.3.0
Fix Version/s: None

Type: Task Priority: Major - P3
Reporter: Tareq Nabeel Assignee: Unassigned
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

The updateOne command below works with MongoDB Java driver 3.3.0 but does not work with MongoDB Async Java driver 3.3.0.

MongoAsync Driver does not work:

	public void upsertForReal(MongoCollection<Document> mCollection, Document query, Document upsert) {
		mCollection.updateOne(query, upsert, new UpdateOptions().upsert(true), new SingleResultCallback<UpdateResult>() {
			@Override
			public void onResult(UpdateResult result, Throwable e) {
				if (e!=null) {
					log.error("Upsert failed", e);	
				}
				if (log.isDebugEnabled()) {
					log.debug("The upsert query "+query+" returned matchedCount="+result.getMatchedCount()+ " modifiedCount= "+result.getModifiedCount());
				}
									
			}
		});
	}

Mongo driver works:

	public void upsertForReal(MongoCollection<Document> mCollection, Document query, Document upsert) {
		mCollection.updateOne(query, upsert, new UpdateOptions().upsert(true));
	}

The MongoAsync driver does not report any issues. The document simply does not get inserted if the query document does not match.



 Comments   
Comment by Jeffrey Yemin [ 29/Aug/16 ]

Not a problem. Just add a comment if you find anything relevant.

Comment by Tareq Nabeel [ 29/Aug/16 ]

I'm unable to reproduce this issue in a standalone program.

I'm now unable to reproduce this in my application as well. I went through a series of changes.. .I can't remember the exact combination that produced the issue:

  • Using replaceOne vs updateOne
  • Having a record already in database that matches query and not having one
  • Using $inc for a count field and using $set for a different field (two separate operations)

For a brief moment last week, when I had zero records in my collection and I used MongoAsync upsert/updateOne, I was not getting my record inserted. I replaced the client with Mongo and it worked. I have a wrapper around the two interfaces (MongoDbAsync/MongoDb), so it's easy for me to switch back and forth. I went back-n-forth last week between the two interfaces and I was consistently getting success with MongoDb and failure with MongoDbAsync. That's what prompted me to create the ticket.

I have since made more changes in my application. Not sure if that's why it's now working with MongoDbAsync.

I'll keep any eye on this and re-open the ticket with more details next time should I see it again. I will make sure to reproduce it in a standalone program before re-opening it.

We can close the ticket for now. Sorry for wasting your time.

Comment by Tareq Nabeel [ 22/Aug/16 ]

Jeff,
Thanks for looking into this. Please give me a couple of days and I'll try to reproduce it in a standalone program.

Comment by Jeffrey Yemin [ 22/Aug/16 ]

Hi Tareq,

I'm not able to reproduce this with the following test program:

        MongoClient client = MongoClients.create();
        MongoCollection<Document> collection = client.getDatabase("test").getCollection("JAVA2284");
 
        // 1. drop the collection first to get consistent results
        CountDownLatch dropLatch = new CountDownLatch(1);
        collection.drop((result, t) -> {
            dropLatch.countDown();
        });
        dropLatch.await();
 
        // 2. do the upsert
        CountDownLatch upsertLatch = new CountDownLatch(1);
 
        Bson query = Filters.eq("_id", 1);
        Bson upsert = Updates.set("x", true);
        collection.updateOne(query, upsert, new UpdateOptions().upsert(true), (result, e) -> {
            if (e != null) {
                e.printStackTrace();
            }
            if (result != null) {
                System.out.println("Upserted Id: " + result.getUpsertedId());
            }
            upsertLatch.countDown();
        });
 
        upsertLatch.await();
 
        // 3. Prove the document was upserted
        CountDownLatch findOneLatch = new CountDownLatch(1);
        collection.find(query).first((result, t) -> {
            System.out.println(result);
            findOneLatch.countDown();
        });
 
        findOneLatch.await();

The output is:

Upserted Id: BsonInt32{value=1}
Document{{_id=1, x=true}}

Can you provide a complete test program that demonstrates the incorrect behavior?

Generated at Thu Feb 08 08:56:49 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.