Why does mgo not return the ID of inserted document?
Asked Answered
H

3

28

According to the documentation (http://godoc.org/launchpad.net/mgo/v2) you can obtain the ID of your "Upserted" document if you use the Upsert method.

There is also an Insert method that does not provide this functionality.
Why is that? What if I want to perform an Insert instead of an Upsert? (or wouldn't ever be any valid reason to want to do that? I'm starting to wonder.)

Halcomb answered 17/8, 2012 at 16:9 Comment(0)
I
47

You use bson.NewObjectId() to generate an ID to be inserted.

This is how you'd insert a new document:

i := bson.NewObjectId()
c.Insert(bson.M{"_id": i, "foo": "bar"})

Since you don't know if you're going to insert or update when you issue an Upsert, it would be superfluous to generate an ID just to drop it right after the query (in case an update happens). That's why it's generated db-side and returned to you when applicable.

Inutility answered 17/8, 2012 at 19:35 Comment(5)
How could I replace "foo":"bar" with a struct I have already created?Cankerous
"If the application is restarted, the Object Id generator will start from the beginning generating the same IDs again and again, thus updating existing records in the database." this is posted on the second answer, is REALLY important and is not mentioned on the answer. I think you should edit the answer adding this information for people in the future.Coel
@Coel This is not true (any more ?). If you look at the implementation of bson.ObjectId, you will see that it takes the current time into account. This is also explained here: github.com/go-mgo/mgo/issues/392Elle
@acidic probably: i := bson.NewObjectId() c.Insert(bson.M{"_id": i}, yourStruct)Vivienviviene
You say "when applicable". In my experience null is returned if the record already existed and was updated; only when a record is created does upsertedId actually have a value. Not what I would expect, nor what the documentation says.Gallon
P
3

This should not happen at all, the mgo should insert and return the Id, since, if we generated the ObjectId from the application itself, If the application is restarted, the Object Id generator will start from the beginning generating the same IDs again and again, thus updating existing records in the database.

That is wrong, MGO should rely on the database in generating those IDs and updating the object or returning the objectId of the inserted object immediately like what other languages binding to MongoDB does like in Python or Java.

Preparedness answered 27/8, 2016 at 16:54 Comment(2)
If instead of bson.NewObjectId() one would use bson.NewObjectIdWithTime(time.Now()) the issue of restarting the application wouldn't be a problem, right?Memoirs
This seems rather impossible reading the ObjectID doc as the method to generate an ObjectID includes a timestamp and PID. If you happen to get the sample PID and reset your system clock then you could potentially get ObjectID clashes, otherwise your fine. docs.mongodb.com/manual/reference/method/ObjectIdEan
D
1

You can always try the Upsert function to get the generated ID.

db := service.ConnectDb()
sessionCopy := db.Copy()
defer sessionCopy.Close() // clean up

collection := sessionCopy.DB(service.MongoDB.DTB).C(MessageCol.tbl)

log.Println("before to write: ", msg)

// Update record inserts and creates an ID if wasn't set (Returns created record with new Id)
info, err := collection.Upsert(nil, msg)
if err != nil {
    log.Println("Error write message upsert collection: ", err)
    return MessageMgo{}, err
}

if info.UpsertedId != nil {
    msg.Id = info.UpsertedId.(bson.ObjectId)
}

// gets room from mongo
room, err := GetRoom(msg.Rid)
if err != nil {
    return msg, err
}

// increments the msgcount and update it
room.MsgCount = room.MsgCount + 1
err = UpdateRoom(room)
if err != nil {
    return msg, err
}

return msg, err

This is a sample code I have and works fine.....

Decompensation answered 7/1, 2018 at 8:11 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.