在Golang中使用LEFT JOIN并映射到一个结构体。

huangapple go评论81阅读模式
英文:

Using LEFT JOIN on Golang and mapping to a struct

问题

我在Go语言中有以下结构体:

type Struct1 struct {
    ID          int64    `db:"id"`
    InternalID  int64    `db:"internal_id"`
    Structs2    []Struct2
}

type Struct2 struct {
   ID          int64    `db:"id"`
   InternalID  int64    `db:"internal_id"`
   SomeText    string   `db:"some_text"`
}

这两个结构体之间的关系是:一个Struct1只能连接到N个Struct2,通过internal_id进行连接。所以我正在执行以下查询:

SELECT *
FROM struct1 st1
LEFT JOIN struct2 st2 
ON
	st1.internal_id = st2.internal_id 
LIMIT 10
OFFSET (1 - 1) * 10;

在Go中执行这个查询后,我想知道是否可以通过正确映射Struct2数组来创建一个Struct1数组。如果可能的话,我该如何做?提前感谢。

我正在使用Postgres和sqlx。

英文:

I have the following structs on Go:

type Struct1 struct {
    ID          int64    `db:id`
    InternalID  int64    `db:internal_id`
    Structs2    []Struct2
}
type Struct2 struct {
   ID          int64    `db:id`
   InternalID  int64    `db:internal_id`
   SomeText    string   `db:some_text`
}

The relation between this two is: There only can be one Struct1, connect to N Struct2 by the internal_id. So I am doing this query:

SELECT*
FROM struct1 st1
LEFT JOIN struct2 st2 
ON
	st1.internal_id = st2.internal_id 
LIMIT 10
OFFSET (1 - 1) * 10;

By executing this query on Go, I wanna know if i can: Create an array of Struct1, by mapping correctly the array Struct2 on it. If it is possible, how can I do it? Thanks in advance.

I'm using Postgres and sqlx.

答案1

得分: 1

这完全取决于你使用的连接数据库的库/客户端,然而,我从未见过有库支持你尝试做的事情,所以我将提供一个自定义实现供你参考。完全透明地说,我没有测试过这个代码,但希望它能给你一个大致的思路,任何人都可以随意进行修改。

package main

type Struct1 struct {
    ID          int64    `db:id`
    InternalID  int64    `db:internal_id`
    Structs2    []Struct2
}

type Struct2 struct {
    ID          int64    `db:id`
    InternalID  int64    `db:internal_id`
    SomeText    string   `db:some_text`
}

type Row struct {
    Struct1
    Struct2
}

func main() {
    var rows []*Row
    // 使用你所使用的 SQL 客户端将响应解码到 rows 变量中

    // 我们将把 struct1 分组到一个 map 中,然后遍历所有的行,从已经添加到 map 中的行中取出 struct2 的内容,
    // 然后将 struct2 追加到它们上面。这样就有效地将 rows 转换为 struct1 和 struct2 之间的一对多关系。
    mapped := map[int64]*Struct1{}
    for _, r := range rows {
        // map 的键将是 struct1 的内部 ID(这是一对多关系中的“一”)
        if _, ok := mapped[r.Struct1.InternalID]; !ok {
            // 如果这是具有 struct1 的内部 ID 的第一行,请确保初始化键。
            mapped[r.Struct1.InternalID] = &r.Struct1
        }
        // 将 struct2(一对多关系中的“多”)追加到 struct1 的 struct2 数组中。
        mapped[r.Struct1.InternalID].Structs2 = append(mapped[r.Struct1.InternalID].Structs2, r.Struct2)
    }

    // 如果需要,将其转换为切片
    results := make([]*Struct1, len(mapped))
    i := 0
    for _, v := range mapped {
        results[i] = v
        i++
    }
}

希望对你有所帮助!

英文:

This is entirely dependent on the library/client you're using to connect to the database, however, I have never seen a library support what you're trying to do so I'll provide a custom implementation that you can do. Full disclosure, I did not test this but I hope it gives you the general idea and anyone should feel free to add edits.

package main

type Struct1 struct {
	ID          int64    `db:id`
	InternalID  int64    `db:internal_id`
	Structs2    []Struct2
}

type Struct2 struct {
	ID          int64    `db:id`
	InternalID  int64    `db:internal_id`
	SomeText    string   `db:some_text`
}

type Row struct {
	Struct1
	Struct2
}

func main() {
	var rows []*Row
	// decode the response into the rows variable using whatever SQL client you use

	// We'll group the struct1s into a map, then iterate over all the rows, taking the
	// struct2 contents off of rows we've already added to the map and then appending
	// the struct2 to them. This effectively turns rows into one-to-many relationships
	// between struct1 and struct2.
	mapped := map[int64]*Struct1{}
	for _, r := range rows {
		// The key of the map is going to be the internal ID of struct1 (that's the ONE
		// in the one-to-many relationship)
		if _, ok := mapped[r.Struct1.InternalID]; ok {
			// Make sure to initialize the key if this is the first row with struct1's
			// internal ID.
			mapped[r.Struct1.InternalID] = &r.Struct1
		}
		// Append the struct 2 (the MANY in the one-to-many relationship) to the struct1s
		// array of struct2s.
		mapped[r.Struct1.InternalID].Structs2 = append(mapped[r.Struct1.InternalID].Structs2, r.Struct2)
	}

	// Then convert it to a slice if needed
	results := make([]*Struct1, len(mapped))
	i := 0
	for _, v := range mapped {
		results[i] = v
		i++
	}
}

huangapple
  • 本文由 发表于 2021年6月8日 03:39:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/67877766.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定