Storing and Retrieving Lat Long Values Stored as Geography Point Type in Database GoLang

Viewed 27

I am trying to save to my database, latitude and longitude values as the geography point datatype and i want to be able to retrieve the values accordingly. I have implemented the following

my model device.go looks like this

device.go

package models

import (
    "bytes"
    "database/sql/driver"
    "encoding/binary"
    "encoding/hex"
    "fmt"
    "time"

    "gorm.io/gorm"
)

type GeoPoint struct {
    Lat float64 `json:"lat"`
    Lng float64 `json:"lng"`
}

func (p *GeoPoint) String() string {
    return fmt.Sprintf("SRID=4326;POINT(%v %v)", p.Lng, p.Lat)
}

// Scan implements the sql.Scanner interface.
func (p *GeoPoint) Scan(val interface{}) error {
    b, err := hex.DecodeString(string(val.(string)))
    if err != nil {
        return err
    }

    r := bytes.NewReader(b)
    var wkbByteOrder uint8
    if err := binary.Read(r, binary.LittleEndian, &wkbByteOrder); err != nil {
        return err
    }

    var byteOrder binary.ByteOrder
    switch wkbByteOrder {
    case 0:
        byteOrder = binary.BigEndian
    case 1:
        byteOrder = binary.LittleEndian
    default:
        return fmt.Errorf("invalid byte order %d", wkbByteOrder)
    }

    var wkbGeometryType uint32
    if err := binary.Read(r, byteOrder, &wkbGeometryType); err != nil {
        return err
    }

    if err := binary.Read(r, byteOrder, p); err != nil {
        return err
    }

    return nil
}

// Value impl.
func (p GeoPoint) Value() (driver.Value, error) {
    return p.String(), nil
}

type Device struct {
    gorm.Model
    Id                int       `json:"id" gorm:"primaryKey"`
    UserId            int       `json:"user_id" gorm:"uniqueIndex"`
    LatestLocation    GeoPoint  `json:"latest_location" gorm:"type:geography(POINT, 4326)"`
    CreatedAt         time.Time
    UpdatedAt         time.Time
}

I am able to save data to the database and this is how it looks like in the database

Database content

But when i want to retrieve the record with the latitude and longitude, I get wrong data records and i am not sure why.

this is my code

location.go

package apisLocation

import (
    "fmt"
    db "atm/pkg/configs/database"
    models "atm/pkg/models"
    "strconv"

    "github.com/gofiber/fiber/v2"
)

func GetLocation(c *fiber.Ctx) error {
    userId, err := strconv.Atoi(c.Params("userId"))
    if err != nil {
        return c.Status(400).JSON(err.Error())
    }

    if checkIfUserExists(userId) {
        return c.Status(400).JSON(fiber.Map{"error": "User does not exist"})
    }
    var device models.Device
    db.DB.Db.Find(&device, models.Device{UserId: userId})
    return c.Status(200).JSON(fiber.Map{"location": device.LatestLocation})
}

func checkIfUserExists(userId int) bool {
    var device models.Device
    db.DB.Db.Find(&device, models.Device{UserId: userId})
    return device.Id == 0
}

when i run the GetLocation method, the response i get is not accurate, i get a value of this

"location": {
        "lat": 1.7689674224598998e+71,
        "lng": -3.639753837714837e+173
    },

which isn't the lat and long that is saved in the database.

I think somehow when it is being decoded, something changes but i am not sure how to fix this issue.

Any help is appreciated

0 Answers
Related