mongodbspring-data-mongodbmongodb-oplog

In Spring MongoDB update, MonogDB doc replaced/lost fields, becomes empty, oplog "o" for this update has no $set, $unset, has only objectId as in "o2"


Context:

Issue :

After an update operation performed, document in collection lost all the data and kept only ObjectId in it.

Checking the oplog entry found an unusual value, understand that the o2field ObjectId says the object to be updated and ofield says about operations being performed/updated.

In this particular instance o2field has the expected value, but o field also has the same value instead of the update operation details to be done.

Question :

Any idea when can we expect such an oplog as mentioned below without $set or $unset for update operations ?

After this operation, actual document with ObjectId in collection lost all the fields except ObjectId.

{
        "ts" : Timestamp(1596778564, 9),
        "t" : NumberLong(7),
        "h" : NumberLong(0),
        "v" : 2,
        "op" : "u",
        "ns" : "db.collectionName",
        "ui" : UUID("2947862a-8fb7-4342-87d1-a0ab5f8bc0bd"),
        "o2" : {
                "_id" : ObjectId("5f27e94e0174081a3feb5c6b")
        },
        "wall" : ISODate("2020-08-07T05:36:04.402Z"),
        "lsid" : {
                "id" : UUID("cbd4b90f-1bff-4ad1-b4e2-4c286fc25450"),
                "uid" : BinData(0,"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=")
        },
        "txnNumber" : NumberLong(1269),
        "stmtId" : 0,
        "prevOpTime" : {
                "ts" : Timestamp(0, 0),
                "t" : NumberLong(-1)
        },
        "o" : {
                "_id" : ObjectId("5f27e94e0174081a3feb5c6b")
        }
}

The update oplog for the same object few milliseconds ago is given below. Which has the right set of operations.

{
        "ts" : Timestamp(1596778564, 8),
        "t" : NumberLong(7),
        "h" : NumberLong(0),
        "v" : 2,
        "op" : "u",
        "ns" : "db.collectionName",
        "ui" : UUID("2947862a-8fb7-4342-87d1-a0ab5f8bc0bd"),
        "o2" : {
                "_id" : ObjectId("5f27e94e0174081a3feb5c6b")
        },
        "wall" : ISODate("2020-08-07T05:36:04.398Z"),
        "lsid" : {
                "id" : UUID("cbd4b90f-1bff-4ad1-b4e2-4c286fc25450"),
                "uid" : BinData(0,"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=")
        },
        "txnNumber" : NumberLong(1268),
        "stmtId" : 0,
        "prevOpTime" : {
                "ts" : Timestamp(0, 0),
                "t" : NumberLong(-1)
        },
        "o" : {
                "$v" : 1,
                "$set" : {
                        .....
                       .......
                      ......... //All the values to be updated
                }
        }
}

Solution

  • Hope it helps some one facing in Spring-MongoDB as well, as I did.

    Tried following code, It happens when update used in mongoTemplate.updateFirst isn't set with any value while calling. If the line update.set is uncommented works fine. When nothing is set in update, it took it as replacement document.

    @Override
        public void run(String... args) throws Exception {
            customerRepository.deleteAll();
    
            customerRepository.save(new Customer("Bob","S"));
            customerRepository.save(new Customer("Alice","Smith"));
    
            findAll();
    
            Update update = new Update();
    //      update.set("firstName", "Bobby");
    
            Query query = Query.query(Criteria.where("lastName").is("S"));
            mongoTemplate.updateFirst(query, update, "customer");
    
            findAll();
        }
    

    Further checking our code, found that set is called on an update based on CONDITION IF values to set are available or not, it seems to working fine as long as the values are available and set is called on update. If the values are not available to set, set is not called on Update to set the values, which took it as replacement and replaced the entire document in collection.