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

Issue

This Content is from Stack Overflow. Question asked by Kingsley Simon

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

[![enter image description here][1]][1]

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
[1]: https://i.stack.imgur.com/RpDkY.png



Solution

This question is not yet answered, be the first one who answer using the comment. Later the confirmed answer will be published as the solution.

This Question and Answer are collected from stackoverflow and tested by JTuto community, is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?