我是一个Go新手,所以对我很轻松。我来自Rubyland并努力了解这个新领域。
上下文:我们有一个服务,其中有两个端点可以访问多个API,按下数据并将其作为json发回。他们在同一个对象上提供数据,但是他们做了截然不同的事情。唯一的常见属性是uid
。
他们正在共享一个模型,如下所示:
type Item struct {
Uid string `json:"uid"`
Val1 string `json:"param1,omitempty"`
Val2 []NestedVal `json:"param2,omitempty"`
Val5 int `json:"param5,omitempty"`
Val6 string `json:"param6,omitempty"`
Val7 string `json:"param7,omitempty"`
}
type NestedVal struct {
Val3 int `json:"val3,omitempty"`
Val4 string `json:"val4,omitempty"`
}
端点A
的示例响应是:
[
{
"uid": "123",
"val1": "foobar"
"val2": [
{"val3": 666, "val4": "qux"},
{"val3": 666, "val4": "qux"}
]
},
{
"uid": "456",
"val1": "foobar"
"val2": [
{"val3": 666, "val4": "qux"},
{"val3": 666, "val4": "qux"}
]
}
]
端点B
的示例响应是:
[
{
"uid": "123",
"val5": 999
"val6": "bar"
"val7": "baz"
},
{
"uid": "456",
"val5": 999
"val6": "bar"
"val7": "baz"
}
]
现在这些服务作为独立服务存在,因为它们提供的服务略有不同,但现在我们需要将它们作为组合数据集提供,例如:
[
{
"uid": "123",
"val1": "foobar"
"val2": [
{"val3": 666, "val4": "qux"},
{"val3": 666, "val4": "qux"}
],
"val5": 999
"val6": "bar"
"val7": "baz"
},
{
"id": "456",
"val1": "foobar"
"val2": [
{"val3": 666, "val4": "qux"},
{"val3": 666, "val4": "qux"}
],
"val5": 999
"val6": "bar"
"val7": "baz"
}
]
对于它的价值,这是它们的返回方式(对于两个端点基本相同):
func FetchA(uids []string) []Item {
var collection []Item
*... fetching, parsing, and appending to collection ...*
return collection
}
func HandlerA(response http.ResponseWriter, request *http.Request) {
*... pull uids out of qs ...*
collection := fetchA(uids)
responseData, _ := json.Marshal(collection)
*... write the response ...*
}
底线:我有两个类型为[]Item
的数据集。我只想将它们组合在共享的uid
键上。显然我正在接近这个作为Ruby开发人员,将此问题视为“我有两个哈希数组,我想将它们合并到一个共享密钥上” - 我知道这是错误的思维框架,但我很漂亮陷入困境,我知道答案就在我的鼻子底下。
我环顾四周,我见过的答案都没有特别有帮助。我检查了mergeo和go-merge但是找不到覆盖merge-ee的方法。
我认为我真正的问题是对Go数据结构缺乏了解。这就是我在Ruby中将两者结合起来的方式:
(responseA + responseB).group_by{|h| h[:uid]}.map{|k,v| v.reduce(:merge)}
编辑:这是一个Go操场上的粗略模拟https://play.golang.org/p/J0bJMjiM8DR
答案 0 :(得分:0)
我认为你正在使用#34;我有两个哈希数组,我希望将它们合并到一个共享密钥上#34;
然而,在Go中你将负责自己进行合并,因为它们不是group_by类型函数/方法的概念。
func merge(As, Bs []Item) []Item {
if len(As) == 0 {
return Bs
}
bMap := make(map[string]Item)
for _, b := range Bs {
bMap[b.Uid] = b
}
merged := make([]Item, len(As))
for i, a := range As {
if b, ok := bMap[a.Uid]; ok {
a.Val5 = b.Val5 // this and the next two lines could be done
a.Val6 = b.Val6 // using reflection, but if you know the fields
a.Val7 = b.Val7 // then this would be my preferred way.
}
merged[i] = a
}
return merged
}
以下是结果的playground
注意:这不会占用As的空切片,因为合并中没有任何内容。由于我不知道您的应用程序的细节,我不能说这是否可能发生,但如果可以,您将需要考虑它。
对于它的价值,我认为这大约是Verran建议的方法:
https://play.golang.org/p/3EpWlFdB8c6
基本上,让结果在频道上返回,并在获得两个结果时将它们合并。