0

I am trying to add an element to a BasicDBList array and save it back to Mongodb, but when I check the result, it is not written. What did I do wrong? I use java driver version 2.7.2.

DBObject dbObject = coll.findOne(dbQuery);

BasicDBList unreadMsgs = (BasicDBList) dbObject.get("unreadMsgs");

Logger.debug("before incrementing unreadMsgs" + dbObject.toString());

unreadMsgs.add(new BasicDBObject("id", 1).append("unreadMsg", 1));
Logger.debug("after incrementing unreadMsgs : " + dbObject.toString());
coll.save(dbObject);
Logger.debug("check result: " + coll.findOne(dbQuery).toString());

before incrementing unreadMsgs{ "_id" : { "$oid" : "515c5eb88e3278e9c9d55867"} , "unreadMsgs" : [ ]}

after incrementing unreadMsgs : { "_id" : { "$oid" : "515c5eb88e3278e9c9d55867"} , "unreadMsgs" : [ { "id" : 1 , "unreadMsg" : 1}]}

check result: { "_id" : { "$oid" : "515c5eb88e3278e9c9d55867"} , "unreadMsgs" : [ ]}

coolsuntraveler
  • 317
  • 5
  • 13
  • Depending on your configuration you could be reading before the write has actually happened. Have you checked a few seconds later directly from mongo shell? – assylias Apr 04 '13 at 00:22
  • yes, I did check a while later directly from mongo shell. The same result. – coolsuntraveler Apr 04 '13 at 00:28
  • If you use the ACKNOWLEDGED writeconcern (default with MongoClient or if you use a Mongo: `mongo.setWriteConcern(WriteConcern.ACKNOWLEDGED);`) you can check if there was an error: `WriteResult result = coll.save(dbObject);` and see if `result.getError()` returns an error. – assylias Apr 04 '13 at 00:37
  • 1
    Thanks for your method. I found the real problem. Please see my answer. – coolsuntraveler Apr 04 '13 at 21:52

3 Answers3

1

The problem is that the coll.save(dbObject) is not updating anything.

It works as an insert and, since the _id already exists in the collection, you are getting a duplicateKey exception (you are just not seeing it because of configuration).

You have to use an update, here is how

AntonioOtero
  • 1,759
  • 1
  • 14
  • 16
  • If you want your app to catch mongo exceptions try setting the writeconcern of your mongoClient to 1. Possible values are: **-1 NONE** No exceptions are raised, even for network issues- **0 NORMAL** Exceptions are raised for network issues, but not server errors **1 SAFE** Exceptions are raised for network issues, and server errors; waits on a server for the write operation **2 REPLICAS_SAFE** Exceptions are raised for network issues, and server errors; waits for at least 2 servers for the write operation – AntonioOtero Apr 03 '13 at 23:40
  • According to javadoc, DBCollection.save: "Saves an object to this collection (does insert or update based on the object _id)." Since this object already exists, shouldn't save actually do an update operation? [This question] (http://stackoverflow.com/questions/11717660/mongodb-java-api-difference-between-com-mongodb-dbcollection-save-and-com-mon) says something similar. – coolsuntraveler Apr 03 '13 at 23:52
  • I ran your code and it works for me as is. I still recommend you use update explicitly. Just replace your coll.save with `coll.update(new BasicDBObject("_id",dbObject.get("_id")), dbObject);` – AntonioOtero Apr 04 '13 at 15:18
1

The save call should work on that case, but I suggest you use an update with $addToSet operation.

Here's the code:

DBObject addToSetObj = BasicDBObjectBuilder.start()
    .push("$addToSet")
        .push("unreadMsgs")
            .add("id", 1)
            .add("unreadMsg", 1)
        .pop()
    .pop()
.get();

// addToSetObj will be { "$addToSet" : { "unreadMsgs" : { "id" : 1 , "unreadMsg" : 1}}}


coll.update(dbQuery, addToSetObj);
Logger.debug("check result: " + coll.findOne(dbQuery).toString());

Any doubts on how to use addToSet, check this out: http://docs.mongodb.org/manual/reference/operator/addToSet/

Miguel Cartagena
  • 2,576
  • 17
  • 20
1

Thanks for everybody's answer. I found the real problem. It turns out that my collection is capped, and I am not allowed to insert more data into an existing document in a capped collection. I saw the exception after I changed WriteConcern to FSYNC_SAFE. I changed all my collections to uncapped, and the code works now.

coolsuntraveler
  • 317
  • 5
  • 13