FindOneAndUpdate by a string _id return error: an ObjectID string must be exactly 12 bytes long

Hello,
I create a collection with the _id in string, normally the _id is 3 characters. When I search the doc by _id, by the function FindOne, I can always get result. But we I find and update a doc by the function FindOneAndUpdate, with the same ID, I will get error message “an ObjectID string must be exactly 12 bytes long (got 3)”. The update operation is just to change a counter of the doc, and I am sure that the counter has been changed successfully, as I can check the changes happened from compass. So the things looks weird, the value changed successfully but db return an error.

The version of my database v3.6.17.

Can anyone give some hint to fix the problem?

Regards,

James

Hi,

Can you give us a code sample to work with? Three characters is not a valid ObjectID, so my guess is that the update is executing successfully, but you’re decoding the result into a struct where the field type is primitive.ObjectID, which fails. A code sample would help to figure out the root cause, though.

– Divjot

Hello Divjot, nice to meet you again. I hope you are doing well and are safe.

//The code here is the API that will access db by id in string
func FindAndUpdateDocByStringID(coll *mongo.Collection, id string, update bson.M, result interface{}) error {
	prefix := coll.Name()
	err := coll.FindOneAndUpdate(context.TODO(), bson.D{{Key: "_id", Value: id}}, update).Decode(result)
	if err != nil {
		if strings.Contains(err.Error(), NoDocument) {
			return errors.NotFound(prefix+"_not_found", err.Error())
		}
		return errors.InternalServerError(prefix+"_internal_error", err.Error())
	}
	return nil
}

//The code here is the calling of the API
	update := bson.M{"$inc": bson.M{"nbr_details_views": 1}}
	modelPlace := Place{}
	err := dboperate.FindAndUpdateDocByStringID(collection, in.Value, update, &modelPlace)

//The code here is the definition of the Place
type Place struct {
	// Id of the Place
	ID string `json:"id,omitempty" bson:"_id,omitempty"`
	// UserID of the owner of the Place
	UserID primitive.ObjectID `json:"user_id,omitempty" bson:"user_id,omitempty"`
	// City of the Place
	City string `json:"city,omitempty" bson:"city,omitempty"`
	// Description of the Place (long text)
	Description string `json:"description,omitempty" bson:"description,omitempty"`
	// Photos lists the available photos URL
	Photos []string `json:"photos,omitempty" bson:"photos,omitempty"`
	// Nbr of views on detail this place
	NbrDetailsViews int32 `json:"nbr_details_views,omitempty" bson:"nbr_details_views,omitempty"`
}

This error comes from the part of the code that tries to decode strings as ObjectIDs, so my guess is that it’s coming from the Decode call when decoding the UserID field as that’s the only field in the Place struct of type primitive.ObjectID. If you can easily reproduce this, it would be really helpful if you could replace the Decode call with DecodeBytes and print the result. That will return a bson.Raw that shows the exact document being returned by the server and can show us which field is causing the error.

– Divjot

1 Like