[GODRIVER-2766] Fail to retrieve a document with a map[primitive.ObjectID]interface{} field Created: 02/Mar/23  Updated: 28/Oct/23  Resolved: 21/Mar/23

Status: Closed
Project: Go Driver
Component/s: None
Affects Version/s: 1.11.2
Fix Version/s: 1.11.4

Type: Bug Priority: Major - P3
Reporter: g.degiorgio Centrica Assignee: Preston Vasquez
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
related to GODRIVER-1330 Document interface{} unmarshalling be... Closed
Documentation Changes: Not Needed
Documentation Changes Summary:

1. What would you like to communicate to the user about this feature?
2. Would you like the user to see examples of the syntax and/or executable code and its output?
3. Which versions of the driver/connector does this apply to?


 Description   

Summary

Reading a document from database into a struct with a map[primitive.ObjectID]interface{} give an error if the interface value is an object

Please provide the version of the driver. If applicable, please provide the MongoDB server version and topology (standalone, replica set, or sharded cluster).

Tested on:

Ubuntu server 22 mongod --version:

db version v6.0.4
Build Info: {
    "version": "6.0.4",
    "gitVersion": "44ff59461c1353638a71e710f385a566bcd2f547",
    "openSSLVersion": "OpenSSL 1.1.1f  31 Mar 2020",
    "modules": [],
    "allocator": "tcmalloc",
    "environment":

{         "distmod": "ubuntu2004",         "distarch": "x86_64",         "target_arch": "x86_64"     }

}

Windows 11 mongod --version

db version v6.0.0
Build Info: {
    "version": "6.0.0",
    "gitVersion": "e61bf27c2f6a83fed36e5a13c008a32d563babe2",
    "modules": [],
    "allocator": "tcmalloc",
    "environment":

{         "distmod": "windows",         "distarch": "x86_64",         "target_arch": "x86_64"     }

}

 

How to Reproduce

 

func NewDB(host string, port string, dbName string) (db *DB) {
   db = new(DB)
   db.DbName = dbName
   db.Host = host
   db.Port = port
   db.mongoUrl = "mongodb://" + host + ":" + port
   return db
}
 
type DB struct {
   DbName   string
   Host     string
   Port     string
   mongoUrl string
   client   *mongo.Client
}
 
func (d *DB) Connect() (err error) {
   log.Println("connecting to: " + d.mongoUrl)
   ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   defer cancel()
   d.client, err = mongo.Connect(ctx, options.Client().ApplyURI(d.mongoUrl))
   return err
}
 
func (d *DB) Disconnect() {
   ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
   defer cancel()
   _ = d.client.Disconnect(ctx)
}
 
func (d *DB) FindOne(collection string, query interface{}, doc interface{}) (found bool, err error) {
   coll := d.client.Database(d.DbName).Collection(collection)
   ctx := context.Background()
   err = coll.FindOne(ctx, query).Decode(doc)
   if err == mongo.ErrNoDocuments {
      return false, nil
   }
   return err == nil, err
}
 
func (d *DB) Insert(collection string, doc interface{}) (err error) {
   coll := d.client.Database(d.DbName).Collection(collection)
   ctx := context.Background()
   _, err = coll.InsertOne(ctx, doc)
   return err
} 
 
func main() {
   db := mongo.NewDB("localhost", "27017", "testdb")
 
   err := db.Connect()
   if err != nil {
      panic(err)
   }
   defer db.Disconnect()
 
   item := &struct {
      A map[primitive.ObjectID]interface{} `json:"foo" bson:"foo"`
   }{}
 
   jsonData := "{ \"foo\" : {\"63ea2082b1ce23422a8bf9ca\" : { \"bar\" : \"\" } } }"
 
   err = json.Unmarshal([]byte(jsonData), item)
   if err != nil {
      fmt.Println("json unmarshal err", err.Error())
   }
 
   err = db.Insert("test", item)
   if err != nil {
      fmt.Println("db insert err", err.Error())
   }
 
   _, err = db.FindOne("test", bson.M{}, item)
   if err != nil {
      fmt.Println("db find err", err.Error())
   }
 
}

console:

 

 

db find error decoding key foo.63ea2082b1ce23422a8bf9ca: the provided hex string is not a valid ObjectID 

 

 



 Comments   
Comment by Githook User [ 04/Apr/23 ]

Author:

{'name': 'Preston Vasquez', 'email': 'prestonvasquez@icloud.com', 'username': 'prestonvasquez'}

Message: GODRIVER-2766 support inherited defaultDocumentType (#1202)
Branch: release/1.11
https://github.com/mongodb/mongo-go-driver/commit/6119f96cc9d361264b82f549019046af7ad9980b

Comment by Preston Vasquez [ 21/Mar/23 ]

g.degiorgio@centrica.it Thank you for reaching out. In version 1.10.0 of the Go Driver, we introduced a work-around intended to default empty types into either primitive.M or primitive.D. It’s worth noting that there is no encodable value for a “BSON Map”; all maps are encoded as embedded documents. In your case, since the “embedded map” is an empty interface, we can only tell the decoder to default it to primitive.M or primitive.D. After investigating this ticket we uncovered a bug that prevents this logic from taking effect on struct types. Therefore, there are two solutions to your problem

(1) You can type the empty interface, i.e.

	type bar struct {
		Bar string
	}
 
	item := &struct {
		A map[primitive.ObjectID]*bar `json:"foo" bson:"foo"`
	}{}

(2) Wait for v1.11.4 of the Go Driver and use a custom decoder to default embedded documents as a map (or a document):

func main() {
	db := mongo.NewDB("localhost", "27017", "testdb")
 
	err := db.Connect()
	if err != nil {
		panic(err)
	}
	defer db.Disconnect()
 
	item := &struct {
		A map[primitive.ObjectID]interface{} `json:"foo" bson:"foo"`
	}{}
 
	jsonData := "{ \"foo\" : {\"63ea2082b1ce23422a8bf9ca\" : { \"bar\" : \"\" } } }"
 
	dec, err := NewDecoder(bsonrw.NewBSONDocumentReader([]byte(jsonData)))
	if err != nil {
		t.Fatal(err)
	}
 
	dec.DefaultDocumentM()
 
	if err := dec.Decode(item); err != nil {
		t.Fatal(err)
	}
 
	err = db.Insert("test", item)
	if err != nil {
		fmt.Println("db insert err", err.Error())
	}
 
	_, err = db.FindOne("test", bson.M{}, item)
	if err != nil {
		fmt.Println("db find err", err.Error())
	}
}

Comment by Githook User [ 21/Mar/23 ]

Author:

{'name': 'Preston Vasquez', 'email': 'prestonvasquez@icloud.com', 'username': 'prestonvasquez'}

Message: GODRIVER-2766 support inherited defaultDocumentType (#1202)
Branch: master
https://github.com/mongodb/mongo-go-driver/commit/1a78435c66fc651202c3050b681d923bab8651c6

Generated at Thu Feb 08 08:39:19 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.