Golang Reflect.DeepEqual 错误结果。将map[string]interface{}中每个键的primitive.A转换为[]interface{}

问题描述 投票:0回答:1

我比较了两个相同的 json 文档。一份来自 Gin,一份来自 MongoDB。 数据类型为:

map[string]interface{}

比较结果为假,而应该为真。

res := reflect.DeepEqual(Data, result)

我使用以下代码来查看差异:

fmt.Printf("expectedjson: %#v\n", result)
fmt.Printf("unmarshalled: %#v\n", data)

结果:

expectedjson: map[string]interface {}{"Connections":primitive.A{}, "Devices":primitive.A{map[string]interface {}{"GUID":"1234", "bmk":"RevPi Core V1.2", "comment":"This is a RevPiCore Device", "extend":map[string]interface {}{}, "id":"1234", "inp":map[string]interface {}{"0":primitive.A{"RevPiStatus", "0", "8", "0", true, "0000", "", ""}, "1":primitive.A{"RevPiIOCycle", "0", "8", "1", true, "0001", "", ""}, "2":primitive.A{"RS485ErrorCnt", "0", "16", "2", false, "0002", "", ""}, "3":primitive.A{"Core_Temperatur", "0", "8", "4", false, "0003", "", ""}, "4":primitive.A{"Core_Frequency", "0", "8", "5", false, "0004", "", ""}}, "inpVariant":0, "mem":map[string]interface {}{}, "name":"RevPi Core V1.2", "offset":0, "out":map[string]interface {}{"0":primitive.A{"RevPiLED", "0", "8", "6", true, "0005", "", ""}, "1":primitive.A{"RS485ErrorLimit1", "10", "16", "7", false, "0006", "", ""}, "2":primitive.A{"RS485ErrorLimit2", "1000", "16", "9", false, "0007", "", ""}}, "outVariant":0, "position":"0", "productType":"95", "type":"BASE"}}}

unmarshalled: map[string]interface {}{"Connections":[]interface {}{}, "Devices":[]interface {}{map[string]interface {}{"GUID":"1234", "bmk":"RevPi Core V1.2", "comment":"This is a RevPiCore Device", "extend":map[string]interface {}{}, "id":"1234", "inp":map[string]interface {}{"0":[]interface {}{"RevPiStatus", "0", "8", "0", true, "0000", "", ""}, "1":[]interface {}{"RevPiIOCycle", "0", "8", "1", true, "0001", "", ""}, "2":[]interface {}{"RS485ErrorCnt", "0", "16", "2", false, "0002", "", ""}, "3":[]interface {}{"Core_Temperatur", "0", "8", "4", false, "0003", "", ""}, "4":[]interface {}{"Core_Frequency", "0", "8", "5", false, "0004", "", ""}}, "inpVariant":0, "mem":map[string]interface {}{}, "name":"RevPi Core V1.2", "offset":0, "out":map[string]interface {}{"0":[]interface {}{"RevPiLED", "0", "8", "6", true, "0005", "", ""}, "1":[]interface {}{"RS485ErrorLimit1", "10", "16", "7", false, "0006", "", ""}, "2":[]interface {}{"RS485ErrorLimit2", "1000", "16", "9", false, "0007", "", ""}}, "outVariant":0, "position":"0", "productType":"95", "type":"BASE"}}}

正如你所看到的,通过从 MongoDB 收集数据并对其进行解码,

[]interface {}
primitive.A
类型。

我使用以下代码来解码来自 MongoDB 的数据:

err = collection.FindOne(context.TODO(), filter, opts).Decode(&result)

比较这些的最佳方法是什么?

我尝试递归遍历整个文档并找到

primitive.A
类型,但我找不到将它们更改为
[]interface {}
的方法。

我使用了这个代码:

walk(reflect.ValueOf(&result))
func walk(v reflect.Value) {
    fmt.Printf("Visiting %v\n", v)
    /*
    code to change primitive.A to interface 
    */

    if v.Elem().Type().String() == "primitive.A" {
        fmt.Println("---", v.Elem(), " : ", v.Elem().Type())
        v.Interface()
        fmt.Println(v.Elem().Type())
    }

    // Indirect through pointers and interfaces
    for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
        v = v.Elem()
    }
    switch v.Kind() {
    case reflect.Array, reflect.Slice:
        for i := 0; i < v.Len(); i++ {
            walk(v.Index(i))
        }
    case reflect.Map:
        for _, k := range v.MapKeys() {
            walk(v.MapIndex(k))
        }
    default:
        // handle other types
    }
}
mongodb go bson
1个回答
0
投票

您似乎正在尝试比较存储在不同数据结构中的 JSON 文档:一份来自 Gin,一份来自 MongoDB,两者都使用数据类型 map[string]interface{}。您正在使用 Reflect.DeepEqual 来比较它们,但它没有给出预期的结果。

从您的描述来看,主要问题似乎是两个文档中的数组(切片)类型不同(primitive.A 与 []interface{})。 Primitive.A 是 MongoDB 的 Go 驱动程序使用的自定义类型,它与标准的 []interface{} 类型不直接匹配。

为了有效地比较这两种结构,您需要进行考虑到这些类型差异的自定义比较。您的递归方法是朝着正确方向迈出的一步,但它需要一些修改来处理 Primitive.A 到 []interface{} 的转换。

以下是如何修改代码来实现此目的:

func walk(v reflect.Value) {
    if v.Type().String() == "primitive.A" {
        // Convert primitive.A to []interface{}
        var result []interface{}
        for i := 0; i < v.Len(); i++ {
            result = append(result, v.Index(i).Interface())
        }
        v.Set(reflect.ValueOf(result))
    }

    // Indirect through pointers and interfaces
    for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
        v = v.Elem()
    }

    switch v.Kind() {
    case reflect.Array, reflect.Slice:
        for i := 0; i < v.Len(); i++ {
            walk(v.Index(i))
        }
    case reflect.Map:
        for _, k := range v.MapKeys() {
            walk(v.MapIndex(k))
        }
    default:
        // handle other types
    }
}

在此代码中,当您遇到primitive.A类型的值时,它将其转换为interface{}的切片并更新反射中的值以匹配所需的结构。此修改应确保两个文档之间的比较按预期进行。

请记住,此方法适用于处理类型差异,但您仍应仔细考虑如何比较文档中的实际值。根据您的用例,您可能还需要处理其他类型和特定字段比较。

© www.soinside.com 2019 - 2024. All rights reserved.