Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upserting in Mongo DB and the Id problem

I have a problem while upserting to mongo db using the official C# driver.

public abstract class AggregateRoot
{
    /// <summary>
    /// All mongoDb documents must have an id, we specify it here
    /// </summary>
    protected AggregateRoot()
    {
        Id = ObjectId.GenerateNewId();
    }

    [BsonId]
    public ObjectId Id { get; set; }
}

My entities already have the id-s but I had to create the mongo specific Id for it to work, as all the documents in a collection should have one. Now then I receive a new entity in my system a new Mongo Id is generated and I get the mongo cannot change _id of a document old exception. Is there some work-around?

Let me describe the design a bit. All the entities which would be stored as documents were inheriting from AggregateRoot which had the id generation in it. Every sub-document had its id generated automatically and I had no problem with this. The id in AggregateRoot was introduced to correct the problem when retrieving data from MongoCollection to List and the generation was introduced so the id-s are different. Now we can move that id generation to save methods because the new entity for update had a new id generation. But it would mean that every dev on the team must not forget generating id-s in repository which is risky. It would be nicer just to ignore the id than mapping from mongo if it is possible and not to have AggregateRoot class at all

like image 686
Yurii Hohan Avatar asked Sep 02 '11 12:09

Yurii Hohan


People also ask

Can we update ID in MongoDB?

You cannot update it but you can save a new id and remove the old id.

Is ID mandatory in MongoDB?

In MongoDB, each document stored in a collection requires a unique _id field that acts as a primary key.

What is the datatype of ID in MongoDB?

MongoDB provides an automatic unique identifier for the _id field in the form of an ObjectId data type. For those that are familiar with MongoDB Documents you've likely come across the ObjectId data type in the _id field.

Can Id be string MongoDB?

Yes, you can. BTW, uniqueness guaranteed by mongodb. Because _id field has a unique index by default.


2 Answers

Looks like you might be explicitly setting the Id value for both inserts and updates. That's fine for inserts, all new objects need an _id value, however for updates you're not allowed to change the value of _id on an existing document after it's created.

Try not setting the Id value at all. If you don't specify a value before inserting, the driver uses built-in IdGenerator classes to generate a new _id value, so if it's an ObjectId type it'll use the ObjectIdGenerator. Then both your inserts and updates work fine.

like image 30
Chris Fulstow Avatar answered Oct 23 '22 11:10

Chris Fulstow


I've encountered similar problem. I wanted to upsert documents using official C# driver. I had a class like this:

public class MyClass
{
    public ObjectId Id { get; set; }
    public int Field1 { get; set; }
    public string Field2 { get; set; }
}

In console I would write: db.collection.update({Field1: 3},{Field1: 3, Field2: "value"}) and it would work. In C# I wrote:

collection.Update(Query.EQ("Field1", 3),
                Update.Replace(new MyClass { Field1 = 3, Field2 = "value" }),
                UpdateFlags.Upsert);

and it didn't work! Because driver includes empty id in update statement and when I upsert second document with different value of Field1 exception E11000 duplicate key error index is thrown (in this case Mongo tries to insert a document with _id that already exists in db).

When I generated _id by myself (like topic starter) I've encountered the same exception (mongo cannot change _id of a document) on upserting objects with existing value of Field1.

Solution is to mark Id property by attribute [BsonIgnoreIfDefault] (and not initialize it). In this case driver omits _id field in update statement and MongoDb generates Id if it necessary.

like image 170
renadeen Avatar answered Oct 23 '22 13:10

renadeen