skip to Main Content

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?

2

Answers


  1. Chosen as BEST ANSWER

    Thanks to Burak Serdar

    Here is the complete example:

    type geojson struct {
        Type        string    `bson:"type"`
        Coordinates []float64 `bson:"coordinates"`
    }
    
    func (g Geolocation) MarshalBSON() ([]byte, error) {
        marshalled, err := bson.Marshal(geojson{"Point", []float64{g.Longitude, g.Latitude}})
        return marshalled, err
    }
    
    func (g *Geolocation) UnmarshalBSON(data []byte) error {
        unmarshalled := geojson{}
        err := bson.Unmarshal(data, &unmarshalled)
        if err != nil {
            return err
        }
        g.Latitude = unmarshalled.Coordinates[1]
        g.Longitude = unmarshalled.Coordinates[0]
        return nil
    }
    

  2. 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
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search