Mysql
 sql >> Database >  >> RDS >> Mysql

Lavorare con i dati spaziali con Gorm e MySQL

Ecco un altro approccio; usa la codifica binaria.

Secondo questo doc , MySQL memorizza i valori della geometria utilizzando 4 byte per indicare lo SRID (Spatial Reference ID) seguito dalla rappresentazione WKB (Well Known Binary) del valore.

Quindi un tipo può utilizzare la codifica WKB e aggiungere e rimuovere il prefisso di quattro byte nelle funzioni Value() e Scan(). La libreria go-geom trovata in altre risposte ha un pacchetto di codifica WKB, github.com/twpayne/go-geom/encoding/wkb.

Ad esempio:

type MyPoint struct {
    Point wkb.Point
}

func (m *MyPoint) Value() (driver.Value, error) {
    value, err := m.Point.Value()
    if err != nil {
        return nil, err
    }

    buf, ok := value.([]byte)
    if !ok {
        return nil, fmt.Errorf("did not convert value: expected []byte, but was %T", value)
    }

    mysqlEncoding := make([]byte, 4)
    binary.LittleEndian.PutUint32(mysqlEncoding, 4326)
    mysqlEncoding = append(mysqlEncoding, buf...)

    return mysqlEncoding, err
}

func (m *MyPoint) Scan(src interface{}) error {
    if src == nil {
        return nil
    }

    mysqlEncoding, ok := src.([]byte)
    if !ok {
        return fmt.Errorf("did not scan: expected []byte but was %T", src)
    }

    var srid uint32 = binary.LittleEndian.Uint32(mysqlEncoding[0:4])

    err := m.Point.Scan(mysqlEncoding[4:])

    m.Point.SetSRID(int(srid))

    return err
}

Definizione di un tag utilizzando il tipo MyPoint:

type Tag struct {
    Name string   `gorm:"type:varchar(50);primary_key"`
    Loc  *MyPoint `gorm:"column:loc"`
}

func (t Tag) String() string {
    return fmt.Sprintf("%s @ Point(%f, %f)", t.Name, t.Loc.Point.Coords().X(), t.Loc.Point.Coords().Y())
}

Creazione di un tag utilizzando il tipo:

tag := &Tag{
    Name: "London",
    Loc: &MyPoint{
        wkb.Point{
            geom.NewPoint(geom.XY).MustSetCoords([]float64{0.1275, 51.50722}).SetSRID(4326),
        },
    },
}

err = db.Create(&tag).Error
if err != nil {
    log.Fatalf("create: %v", err)
}

Risultati MySQL:

mysql> describe tag;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name  | varchar(50) | NO   | PRI | NULL    |       |
| loc   | geometry    | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+


mysql> select name, st_astext(loc) from tag;
+--------+------------------------+
| name   | st_astext(loc)         |
+--------+------------------------+
| London | POINT(0.1275 51.50722) |
+--------+------------------------+
  • (ArcGIS dice 4326 è il riferimento spaziale più comune per la memorizzazione di dati di riferimento in tutto il mondo. Serve come impostazione predefinita sia per il database spaziale PostGIS che per lo standard GeoJSON. Viene anche utilizzato per impostazione predefinita nella maggior parte delle librerie di mappe Web.)