1

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

nanakondor
  • 615
  • 11
  • 25

1 Answers1

1

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?

icza
  • 389,944
  • 63
  • 907
  • 827
  • sorry if i wasnt clear. i mean, if i hardcode my aws config i think its possible but I retrieve it using config.yaml so im not sure how to get them inside the unmarshal function – nanakondor Jan 18 '21 at 10:37
  • Your custom marshaling logic is "plain" Go code, it can access your config. You don't need to hard-code anything into it. – icza Jan 18 '21 at 10:39
  • ohh ok i got it ty. also, if i implement unmarshalbson, is it compulsory i implement marshalbson as well eventhough i only need unmarshal? – nanakondor Jan 18 '21 at 10:42
  • @nanakondor Implement whichever you need. If you only need custom save, implement only `MarshalBSON()`. You don't have to implement both. – icza Jan 18 '21 at 10:49