[GODRIVER-1343] Collection.FindOne is having problems with a struct that has a interface as attribute Created: 13/Oct/19  Updated: 22/Oct/19  Resolved: 22/Oct/19

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

Type: Bug Priority: Major - P3
Reporter: Sunny B Assignee: Isabella Siu (Inactive)
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Attachments: File interface_marshal_unmarshal.go    

 Description   

Hi, 

Based on this issue GODRIVER-1294https://jira.mongodb.org/browse/GODRIVER-1294,

In the same example, when we try to retrieve the document Collection.FindOne is also giving decode errors

"no decoder found for main.Scannable"

 

I see GODRIVER-1294 is addressing as part of https://jira.mongodb.org/browse/GODRIVER-1216

Do we expect the decoding issue also be addressed in GODRIVER-1216?

Please let me know

Thank you



 Comments   
Comment by Divjot Arora (Inactive) [ 22/Oct/19 ]

You can decode into map[string]interface{} (note this is the same as decoding into bson.M). This would yield something like:

map[string]interface{}{
    "_id": <object ID>,
    "status": map[string]interface{}{
        "code": "foo",
        "message": "bar",
    },
}

Another option is to replace the interface field in the struct with a field that has a concrete type (i.e. replace IStatus with Status).

I think we've reached a resolution, so I'm going to close this ticket. Feel free to leave a new comment or open a new ticket if you have any more questions about this.

– Divjot

Comment by Sunny B [ 20/Oct/19 ]

 

Hi divjot.arora

Thanks for the response. I have not seen any libraries for that.

So, In order to avoid the decoding issue, I need to decode the result into map[string]interface{} first and then unmarshal into a concrete model. And if that struct any field had type as a interface{} we need to unmarshal to a corresponding struct.

Do you see any other way?

Thanks,

Sunny

 

Comment by Divjot Arora (Inactive) [ 16/Oct/19 ]

Hi satyababu.b@gmail.com,

Thanks for the code sample. The issue is not with the Container type, but instead with the IStatus field in it. When we get some data from the database that looks like {_id: ObjectID(), status: {code: "foo", message: "bar"}}, it's not possible for the driver to unmarshal the status subdocument into an IStatus type because IStatus has no defined structure. The driver has no way of knowing that the actual type it should unmarshal into is Status, not IStatus.

 

Do you know of any other libraries that accomplish the desired behavior? I've linked a code sample that tries to marshal a struct with an interface field and then unmarshal the result into another struct of the same type using the mgo and encoding/json libraries. For both, the struct can be marshalled but not unmarshalled.

interface_marshal_unmarshal.go

Comment by Sunny B [ 16/Oct/19 ]

Thanks, @isabella.siu for the quick response

I put the example here which is similar to GODRIVER-1294

type Container struct { 
    ID      string    `bson:"_id" valid:"required"` 
    Status  IStatus   `bson:"status"`
}
 
type IStatus interface { 
    // GetCode returns status code 
    GetCode() string 
    // SetCode sets code to status 
    SetCode(code string)
}
 
type Status struct { 
      Code        string `bson:"code,omitempty"` 
      Message     string `bson:"message,omitempty"`
}
 
// GetCode returns status code
func (ref Status) GetCode() string { 
      return ref.Code
}
 
// SetCode sets code to status
func (ref Status) SetDetails(code string) { 
     ref.Code = code
}
 
// code to read the doc from DB
    col := db.Collection("xxxxx"
    ctxt, cancel := context.WithTimeout(ctx, MAX_INSERT_TIMEOUT) 
    defer cancel()     
    result := col.FindOne(ctxt, nil) 
    if result.Err() != nil { 
        log.Errorf("failed to read document -> %v", result.Err()) 
        return result.Err() 
    }
 
  container := &Container{}    
  err := result.Decode(container)//when we decode into concrete object 'Container,it gives err
  if err != nil {        
       log.Errorf("failed to decode document -> %v", err)        
       return err    
    }

 

As I described above, when we decode into Container object,  its giving 
"" no decoder found for IStatus ""

Please let me know

Thanks,
Sunny

Comment by Isabella Siu (Inactive) [ 15/Oct/19 ]

Hi satyababu.b@gmail.com,

What behavior would you expect from decoding into an interface? GODRIVER-1294 will add support for marshalling structs with interfaces by unpacking interface fields until a concrete type is determined. However, there isn't a way for the driver to determine a concrete type for an interface field during unmarshalling.

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