当前位置: 首页 > 面试题库 >

使用Gorm插入和选择PostGIS Geometry

令狐增
2023-03-14
问题内容

我一直在尝试找到一种使用Golang尤其是库gorm插入和检索几何类型的方法。我还尝试使用库orb,它为几何定义了不同的类型,并提供了不同格式之间的编码/解码。

Orb 已经为每种类型实现了Scan()Value()方法。这使得go’s
Insert()Scan()函数可以使用除基本类型以外的其他类型。但是,Orb期望使用以众所周知的二进制(WKB)格式表示的几何。

orb文档显示,要实现此目的,您只需将字段包装在PostGIS函数中ST_AsBinary()ST_GeomFromWKB()并分别用于查询和插入。例如,表定义为:

_, err = db.Exec(`
        CREATE TABLE IF NOT EXISTS orbtest (
            id SERIAL PRIMARY KEY,
            name TEXT NOT NULL,
            geom geometry(POLYGON, 4326) NOT NULL
        );
    `)

您可以这样做:

rows, err := db.Query("SELECT id, name, ST_AsBinary(geom) FROM orbtest LIMIT 1")

对于插入(其中p是orb.Point):

db.Exec("INSERT INTO orbtest (id, name, geom) VALUES ($1, $2, ST_GeomFromWKB($3))", 1, "Test", wkb.Value(p))

这是我的问题:通过使用GORM,我无法使用这些功能来构建那些查询。GORM将自动将给定结构的值插入数据库,并将数据扫描到结构的整个层次结构中。这些Scan()Value()方法被称为幕后,没有我的控制。

尝试将二进制数据直接插入到几何列中是行不通的,而直接查询几何列将以十六进制形式给出结果。

我尝试了多种数据库方法来解决此问题。我试图创建视图,以自动在几何列上调用所需的函数。这适用于查询,但不能插入。

是否可以做出某种触发或规则,以自动对传入/传出的数据调用所需的功能?

我还应该注意,我正在使用的库的工作完全独立于数据和架构,因此我没有进行任何形式的查询硬编码的奢侈。我当然可以编写一个函数来扫描整个数据模型,并从头开始生成查询,但是我希望有更好的选择。

有谁知道用SQL进行这项工作的方法吗?只需查询列本身就能够自动调用列上的函数?

任何建议将不胜感激。


问题答案:

我最终使用的另一个解决方案是go-geos,因为我发现我需要使用GEOS
C库。这样,我就可以将结构转换WKT为要插入的结构(因为postgis将其作为常规文本接受)并可以WKB在扫描时进行转换。

type Geometry4326 *geos.Geometry

// Value converts the given Geometry4326 struct into WKT such that it can be stored in a 
// database. Implements Valuer interface for use with database operations.
func (g Geometry4326) Value() (driver.Value, error) {

    str, err := g.ToWKT()
    if err != nil {
        return nil, err
    }

    return "SRID=4326;" + str, nil
}

// Scan converts the hexadecimal representation of geometry into the given Geometry4326 
// struct. Implements Scanner interface for use with database operations.
func (g *Geometry4326) Scan(value interface{}) error {

    bytes, ok := value.([]byte)
    if !ok {
        return errors.New("cannot convert database value to geometry")
    }

    str := string(bytes)

    geom, err := geos.FromHex(str)
    if err != nil {
        return errors.Wrap(err, "cannot get geometry from hex")
    }

    geometry := Geometry4326(geom)
    *g = geometry

    return nil
}

由于并非每个人都需要使用GEOS C库,因此该解决方案可能并不适合每个人,在Windows上工作可能会很痛苦。我敢肯定,使用不同的库可以完成同一件事。

我还在struct上实现了,UnmarshalJSON()MarshalJSON()使其能够自动将GeoJSON编组/取消编组,然后无缝地从数据库保存/获取。我使用geojson-
go
将GeoJSON与结构进行相互转换,然后使用geojson-
geos-go将上述结构转换为我正在使用的go-
geos结构,从而完成了此任务。有点令人费解,是的,但是有效。



 类似资料:
  • 问题内容: 我是来自python背景的Golang的新手,所以尝试了解新的和不同的概念。我正在尝试创建相关字段,然后从数据库中选择它们。 楷模: 创建表和行并从数据库中选择 打印: 两个问题: 为什么我需要选择creditCard作为单独的变量而不是使用点符号? 我在公司上遇到错误,并且没有点符号或相关工作。我该如何取回? 问题答案: 根据文件,你需要设置以进行自动预加载工作。因此,将检索用户的行

  • 问题内容: 有没有办法插入预设值和我从选择查询中获得的值?例如: 我有“字符串”的值和数字5,但是我必须从这样的选择中找到[int]值: 那给我那个ID放在table1里面。 如何将其合并为一个语句? 问题答案: 使用查询,并将已知值放入:

  • 问题内容: 我想知道以下是否可能。我知道它不起作用,但是也许我没有以正确的语法编写它。 无论如何这样做? 问题答案: 不支持HTML,仅支持文本。您可能应该使用javascript,jQuery或类似的东西。 您的代码的另一个问题是在一个块内。您应该混合使用和()。 如果确实支持HTML,则可能会陷入无限循环,并在其中添加。

  • 问题内容: 有几种将数据插入表中的方法: 有没有办法使用,但我不想在colA中插入例如colAA值,而是总是将其插入1。 感谢帮助 问题答案: 只需在列表中添加一个常量

  • 我有一个包含两列的表:k(主键)和value。我想: 选择k进行更新,如果找不到k,则插入默认值的新行。 对返回的值(存在的或新插入的行值)进行一些处理。 更新行并提交。 是否可以使此“选择更新并在未找到时插入默认值”? 如果将(1)实现为select/check if found/insert if not found,我们会遇到并发问题,因为两个会话可能会在不存在的键上并发地进行选择,两个会话

  • 就像有人说的第二种方式更慢,但我不确定,那么哪种方式更好呢?不能使数据库崩溃。