omitempty behavior differs from how value types are expected to work. Especially objectid.NilObjectID can be quite misleading in such scenarios. Kindly go test the following or use the attached file.
package main import ( "testing" "github.com/mongodb/mongo-go-driver/bson" "github.com/mongodb/mongo-go-driver/bson/objectid" ) type ThingOmitID struct { ID objectid.ObjectID `bson:"_id,omitempty"` Field string `bson:"field"` } type ThingOmitIDPtr struct { ID *objectid.ObjectID `bson:"_id,omitempty"` Field string `bson:"field"` } type ThingOmitStringField struct { ID objectid.ObjectID `bson:"_id"` Field string `bson:"field,omitempty"` } func TestOmitEmptyID_NilObjectID(t *testing.T) { thing := &ThingOmitID{ ID: objectid.NilObjectID, Field: "content", } validateNumKeys(t, 1, thing) } func TestOmitEmptyID_Omit(t *testing.T) { thing := &ThingOmitID{ Field: "content", } validateNumKeys(t, 1, thing) } func TestOmitEmptyIDPtr_Nil(t *testing.T) { thing := &ThingOmitIDPtr{ ID: nil, Field: "content", } validateNumKeys(t, 1, thing) } func TestOmitEmptyIDPtr_NilObjectID(t *testing.T) { thing := &ThingOmitIDPtr{ ID: &objectid.NilObjectID, Field: "content", } validateNumKeys(t, 2, thing) } func TestOmitEmptyStringField_Empty(t *testing.T) { thing := &ThingOmitStringField{ ID: objectid.NilObjectID, Field: "", } validateNumKeys(t, 1, thing) } func TestOmitEmptyStringField_Omit(t *testing.T) { thing := &ThingOmitStringField{ ID: objectid.NilObjectID, } validateNumKeys(t, 1, thing) } func validateNumKeys(t *testing.T, numKeys int, obj interface{}) { encodedObj, err := bson.NewDocumentEncoder().EncodeDocument(obj) if err != nil { t.Error(err.Error()) } keys, err := encodedObj.Keys(false) if err != nil { t.Error(err.Error()) } if numKeys != len(keys) { for _, key := range keys { t.Log(key.Prefix, key.Name) } t.Errorf("Expected number of keys: %d, actual: %d", numKeys, len(keys)) } }