0

Context:

  • Spring Data MongoDB is used and updating a document caused the following issue.

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
                }
        }
}
Mahudees
  • 41
  • 6
  • You had a query that set the document to {_id: 'foo'} ? – D. SM Aug 08 '20 at 14:34
  • No, able to set the values for the document, but in some random update operation entire fields in document is lost with ObjectId alone left. Checking in oplog found that there is no "$set" or "$update" operation in update operation. Wondering when this could be possible. – Mahudees Aug 08 '20 at 17:31
  • See https://docs.mongodb.com/manual/reference/method/db.collection.update/. You are providing the "replacement document". – D. SM Aug 08 '20 at 17:56

2 Answers2

1

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.

Mahudees
  • 41
  • 6
0

One of your applications is providing a "replacement document" as described in https://docs.mongodb.com/manual/reference/method/db.collection.update/. The replacement document consists of the _id only which removes the other fields. There is nothing out of ordinary about the oplog entry you quoted.

D. SM
  • 13,584
  • 3
  • 12
  • 21
  • Tried following code, It happens when 'update' used in 'updateFirst' isn't set with any value while calling. If "update.set" is uncommented works fine. When no update is set, it took it as replacement document. @Override public void run(String... args) throws Exception { customerRepository.save(new Customer("Bob","S")); customerRepository.save(new Customer("Alice","Smith")); Update update = new Update(); // update.set("firstName", "Bobby"); Query query = Query.query(Criteria.where("lastName").is("S")); mongoTemplate.updateFirst(query, update, "customer"); findAll(); } – Mahudees Aug 09 '20 at 09:03