Search code examples
gobsongo-ginpre-signed-urlaws-sdk-go

How to use virtual attributes


I'm storing attachment in mongodb as Attachment object:

type Attachment struct {
  ID   string `bson:"_id" json:"id"`
  Name string `bson:"name" json:"name"`
  URL  string `bson:"url" json:"url"`
}

The URL stored is the presigned URL for PUT request, retrieved using AWS session. In Ruby on Rails, I can use virtual attribute to change the URL to presigned URL for GET request:

// models/attachment.rb
def url
  if super.present?
    // get the presigned URL for get request using the URL from super
  else
    super
  end
end

How can I accomplish this in Go? I have my configs in config.yaml and need to convert yaml to struct. Meanwhile, marshal and unmarshal of BSON only receive data []byte as parameter. I'm not sure how to initiate the AWS session in the marshal and unmarshal of BSON.

I prefer to modify the URL after I query from mongodb, but I want to do it in 1 place


Solution

  • The mongo-go and mgo drivers check for and call certain implemented interfaces when converting Go values to / from BSON values. Implement bson.Marshaler and bson.Unmarshaler on your type and you can do anything before saving it / after loading it.

    Call the default bson.Marhsal() and bson.Unmarshal() functions to do the regular marshaling / unmarshaling process, and if that succeeds, then do what you want before returning.

    For example:

    // Called when an Attachment is saved.
    func (a *Attachment) MarshalBSON() (data []byte, err error) {
        data, err = bson.Marshal(a)
        if err != nil {
            return
        }
    
        // Do your additional thing here
    
        return
    }
    
    // Called when an Attachment is loaded.
    func (a *Attachment) UnmarshalBSON(data []byte) error {
        if err := bson.Unmarshal(data, &a); err != nil {
            return err
        }
    
        // Do your additional thing here
    
        return nil
    }
    

    Also see related: How to ignore nulls while unmarshalling a MongoDB document?