Search code examples
mongodbgogeojson

Can I use surrogate fields in BSON?


Can I make MongoDb replace field representations with a surrogate type?

I would like to have a metadata struct with location. To save conversion back and forth, I want to share the model with my JSON (for the API) and the BSON (for MongoDb).

I could use a struct like

type GeoJson struct {
    Type        string    `bson:"type", json:"type"`
    Coordinates []float64 `bson:"coordinates", json:"coor"`
}

type Metadata struct {
   CaptureTime time.Time `bson:"time", json:"time"`
   Coordinate  GeoJson   `bson:"geo", json:"geo"`
}

But then, I will have to work with GeoJson across my app, which is not comfortable. I would rather use some

type GeoLocation struct {
   Latitude float64 `json:"lat"`
   Longitude float64 `json:"lon"`
}

Which is more "Human-Readable". Especially when GeoJson is reverse (lon, lat as opposed to the common Lat, Lon).

But if I use that for the MongoDb structures - I lose all the geolocation goodies that MongoDb has to offer.

Can I tell MongoDb to map GeoLocation{lat, lon} to GeoJson{type: "point", coordinates:{lon, lat}} upon write, and map the other way round on read?


Solution

  • You should be able to use a custom marshaler/unmarshaler for GeoLocation:

    func (g GeoLocation) MarshalBSON() ([]byte,error) {
       // convert g to GeoJson
       return bson.Marshal(geojson)
    }
    
    func (g *GeoLocation) UnmarshalBSON(b []byte) error {
       var gj GeoJson
       if err:=bson.Unmarshal(b,&gj); err!=nil {
          return err
       }
       // Convert gj back to g
    }