xwill

To be double-cool

23 Mar 2023

go reflect学习

需求: mongo 中的结构,可能会持续进行变更(新增成员) 对外的接口,已经提供出去,期望接口不变,能对数据进行更新。

这个时候可以利用 mongo 的update 和 reflect 完成需求。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import (
	"errors"
	"reflect"
	"strings"
)

var ErrInvalide = errors.New("invalid err")

func extractReflectValueMap(modifyValue reflect.Value, rMap map[string]interface{}) (err error) {
	if !modifyValue.IsValid() || modifyValue.Kind() != reflect.Struct {
		return ErrInvalide
	}

	for i := 0; i < modifyValue.NumField(); i++ {
		tag := modifyValue.Type().Field(i).Tag.Get("json")
		tag = strings.TrimSuffix(tag, ",omitempty")
		if _, ok := rMap[tag]; ok {
			return ErrInvalide
		}
		switch modifyValue.Field(i).Kind() {
		case reflect.Struct:
			sMap := make(map[string]interface{})
			err = extractReflectValueMap(modifyValue.Field(i), sMap)
			if err != nil {
				return
			}
			if tag != "" {
				rMap[tag] = sMap
			} else {
				for k, v := range sMap {
					if _, ok := rMap[k]; ok {
						return ErrInvalide
					}
					rMap[k] = v
				}
			}
		default:
			if tag == "" {
				return ErrInvalide
			}
			rMap[tag] = modifyValue.Field(i).Interface()
		}
	}
	return
}

type ApiData struct {
	Name string `json:"name,omitempty" bson:"name"`
	Age int `json:"age,omitempty" bson:"age"`
}

type YourDB struct {
	ApiData
	AppendMember string `json:"appendMember,omitempty" bson:"appendMember"`
}

func ApiModifyData(data *ApiData) {
	dealMap := make(map[string]interface{})
	if err = extractReflectValueMap(reflect.ValueOf(*data), dealMap); err != nil {
		return
	}

	m := bson.M{}
	for k, v := range dealMap {
		m[k] = v
	}

	yourMongo.update(bson.M{"key": key}, bson.M{"$set": m})
	return
}

伪代码的过程比较简单。 其他还可以补充,数据判断,异常处理等。