使用Golang将两片类似数据合并到JSON中

时间:2018-03-22 22:35:26

标签: go

我是一个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

1 个答案:

答案 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

基本上,让结果在频道上返回,并在获得两个结果时将它们合并。