6

I'm trying to build MongoDB Java findAndModify query.

The main purpose is that I would like to set _id in insert query by myself.

Here is my code:

BasicDBObject findFilter = new BasicDBObject("type", "group")
//
BasicDBObject dialogInsertObject = new BasicDBObject("name", "my group").append("_id", new ObjectId());
//
BasicDBObject dialogUpdateObject = new BasicDBObject("name", "my group");
//
BasicDBObject upsertMap = new BasicDBObject();
upsertMap.append("$setOnInsert", dialogInsertObject);
upsertMap.append("$set", dialogUpdateObject);


DBObject dialogObject = dialogCollection.findAndModify(findFilter, 
   new BasicDBObject("_id", "1"), null, false, upsertMap, true, true);

And I get an error:

com.mongodb.CommandFailureException: { "serverUsed" : "localhost:27017" , 
  "errmsg" : "exception: Cannot update 'name' and 'name' at the same time" , 
  "code" : 16836 , "ok" : 0.0}

Can somebody help please

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
Rubycon
  • 18,156
  • 10
  • 49
  • 70
  • Pretty much as the error says. You cannot set both the same things within `$setOnInsert` and `$set` at the same time. Also your `dialogInsertObject` values are overwriting. – Neil Lunn Jun 02 '14 at 11:07
  • sorry, updated dialogInsertObject. Why I can't use $set and $setOnInsert in single query? – Rubycon Jun 02 '14 at 11:37
  • @NeilLunn as documentation says, $setOnInsert is for insert, but $set is for update operation. What's wrong? – Rubycon Jun 02 '14 at 11:39
  • @NeilLunn read http://docs.mongodb.org/manual/reference/operator/update/setOnInsert/ Upsert Results in an Update – Rubycon Jun 02 '14 at 11:43
  • Not the person you should be saying "read the docs to" as I am sure I know them a lot better than most. You can use both terms the problem is you are using the same "field" in both. Calm down and read what I said in the first place if not this. – Neil Lunn Jun 02 '14 at 11:49
  • @NeilLunn common man, you didn't provide much info in your 1st comment. Would you like to say that $set operator also works for insert operation? – Rubycon Jun 02 '14 at 12:09
  • This reallt should have been clear but now you have an answer to really make it clear what you are trying to do – Neil Lunn Jun 02 '14 at 12:21

1 Answers1

9

The essential problem here is this:

db.collection.update(
   { "type": "group" },
   { 
      "$set": { "mygroup": "value" }
      "$setOnInsert" { "mygroup": "value" }
   }
)

Which is basically what you are trying to do.

You cannot address the same field in a $set operation as a $setOnInsert operation.

There is a general problem in the logic that causes the error you are experiencing.

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
  • so, I should include _id only to $setOnInsert and this a right solution. Thanks – Rubycon Jun 02 '14 at 12:51
  • 1
    @IgorKhomenko The bottom line is that if you reference the **same** thing in both statements you are causing a conflict when something is actually inserted. But I hope you see that now. – Neil Lunn Jun 02 '14 at 12:59
  • 1
    This bit me as well, and the first comment is wrong. You should only specify it in the $set block, since $set is applied even when it's inserting a new document. They are not mutually exclusive (being familiar with MySQL ON DUPLICATE KEY syntax confused me). – jishi Nov 02 '16 at 15:19