重命名的JSON字段

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

Renamed JSON field

问题

我们想要在生产环境中将一个JSON字段value重命名为v。在所有用户都使用新的结构之前,我们将继续接收旧的JSON结构到我们的代码中。因此,我们也希望处理这个问题。

如果你注意到,First是原始结构,Second是新的结构。为了处理这两个结构,我创建了一个MyStruct,根据version的值,将OldValue复制到Value中。

if m.Version <= 1 {
    m.Value = m.OldValue
}

有没有更好的方法来处理这个问题,而不是使用我的代码。

Go Playground链接

package main

import "fmt"
import "encoding/json"
import "log"

type First struct {
    Version int `json:"version"`
    Value   int `json:"value"`
}

type Second struct {
    Version int `json:"version"`
    Value   int `json:"v"`
}

type MyStruct struct {
    Version  int `json:"version"`
    OldValue int `json:"value"`
    Value    int `json:"v"`
}

func main() {
    oldValue := []byte(`{"version":1, "value":5}`)
    newValue := []byte(`{"version":2, "v":7}`)

    var m MyStruct

    err := json.Unmarshal(newValue, &m)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("New Struct")
    fmt.Println(m.Value)

    err = json.Unmarshal(oldValue, &m)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Old Struct")
    if m.Version <= 1 {
        m.Value = m.OldValue
    }
    fmt.Println(m.Value)
}
英文:

We want to rename a JSON field value to v in production. Till all our users use the new struct, we would continue to get old JSON structs into our code. So we want to handle this as well.

If you notice, First is the original structure, Second is the new structure. To handle both these structures, I have created a MyStruct and based on version, I copy the OldValue into Value

if m.Version &lt;= 1 {
	m.Value = m.OldValue
}

Is there a better way to handle this, instead of my code.

Go Playground Link

package main

import &quot;fmt&quot;
import &quot;encoding/json&quot;
import &quot;log&quot;

type First struct {
	Version int `json:&quot;version&quot;`
	Value   int `json:&quot;value&quot;`
}

type Second struct {
	Version int `json:&quot;version&quot;`
	Value   int `json:&quot;v&quot;`
}

type MyStruct struct {
	Version  int `json:&quot;version&quot;`
	OldValue int `json:&quot;value&quot;`
	Value    int `json:&quot;v&quot;`
}

func main() {
	oldValue := []byte(`{&quot;version&quot;:1, &quot;value&quot;:5}`)
	newValue := []byte(`{&quot;version&quot;:2, &quot;v&quot;:7}`)

	var m MyStruct

	err := json.Unmarshal(newValue, &amp;m)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(&quot;New Struct&quot;)
	fmt.Println(m.Value)

	err = json.Unmarshal(oldValue, &amp;m)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(&quot;Old Struct&quot;)
	if m.Version &lt;= 1 {
		m.Value = m.OldValue
	}
	fmt.Println(m.Value)

}

答案1

得分: 1

你可以使用一次解组来实现,尽管你需要另一个类型:

type Second struct {
    Version int `json:"version"`
    Value   int `json:"v"`
}

type SecondWithOldValue struct {
    OldValue int `json:"value"`
    Second
}

type MyStruct SecondWithOldValue

func (v *MyStruct) UnmarshalJSON(b []byte) error {
    if err := json.Unmarshal(b, (*SecondWithOldValue)(v)); err != nil {
        return err
    }

    if v.Version <= 1 {
        v.Value = v.OldValue
    }
    return nil
}

Playground: https://play.golang.org/p/yII-ncxnU4

以下是旧的回答。

如果你可以接受双重解组,可以这样做:

type Second struct {
    Version int `json:"version"`
    Value   int `json:"v"`
}

type MyStruct struct {
    Second
}

func (v *MyStruct) UnmarshalJSON(b []byte) error {
    if err := json.Unmarshal(b, &v.Second); err != nil {
        return err
    }

    if v.Version <= 1 {
        var oldV struct{ Value int }
        if err := json.Unmarshal(b, &oldV); err != nil {
            return err
        }
        v.Value = oldV.Value
    }
    return nil
}

首先,解组到内部结构体,检查版本,如果是旧版本,则获取旧值。

Playground: https://play.golang.org/p/AaULW6vJz_

英文:

EDIT: You can actually do it with one unmarshaling, albeit you'll need another type:

type Second struct {
	Version int `json:&quot;version&quot;`
	Value   int `json:&quot;v&quot;`
}

type SecondWithOldValue struct {
	OldValue int `json:&quot;value&quot;`
	Second
}

type MyStruct SecondWithOldValue

func (v *MyStruct) UnmarshalJSON(b []byte) error {
	if err := json.Unmarshal(b, (*SecondWithOldValue)(v)); err != nil {
		return err
	}

	if v.Version &lt;= 1 {
		v.Value = v.OldValue
	}
	return nil
}

Playground: https://play.golang.org/p/yII-ncxnU4.

Old answer below.


If you're OK with double unmarshaling, you can do it like this:

type Second struct {
	Version int `json:&quot;version&quot;`
	Value   int `json:&quot;v&quot;`
}

type MyStruct struct {
	Second
}

func (v *MyStruct) UnmarshalJSON(b []byte) error {
	if err := json.Unmarshal(b, &amp;v.Second); err != nil {
		return err
	}

	if v.Version &lt;= 1 {
		var oldV struct{ Value int }
		if err := json.Unmarshal(b, &amp;oldV); err != nil {
			return err
		}
		v.Value = oldV.Value
	}
	return nil
}

First, unmarshal into the inner struct, check version, and if it's an old one, get the old value.

Playground: https://play.golang.org/p/AaULW6vJz_.

答案2

得分: 0

我会选择不在这里使用三个不同的结构体,因为它们实际上都是相同的。

按照你修改的方式修改你的结构体MyStruct,并将json:"value"加载到一个新变量中,同时在解组过程中,如果Value不存在,将值复制到Value变量中。

然而,我赞同Kostix的建议。你的API或加载和保存数据的过程应该尝试通过建议的机制来考虑版本控制。在URI中添加一个v#,或者如果你将项目保存到磁盘中,可以使用版本号保存,并根据正确版本对应的结构体处理内部部分:

{
    "version": 1,
    "struct": { ... }
}
英文:

I would opt to not use 3 different struct here as they are all the same really.

Modify your struct MyStruct as you have and load the json:&quot;value&quot; into a new variable as you are and part of your Unmarshal should copy the value into the Value variable if Value is not present.

However I would second Kostix's recommendation here. Your API or process that loads and saves data should try to account for versioning by the mechanism suggested. Add a v# to your URI or if you're saving the item down to disk, then perhaps save it with a version number as such and then process the inner section per struct that corresponds to the proper version:

{
    &quot;version&quot;: 1,
    &quot;struct&quot;: { ... }
}

huangapple
  • 本文由 发表于 2015年10月20日 19:57:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/33236040.html
匿名

发表评论

匿名网友

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

确定