我有来自数据库的数据是json.RawMessage格式的.具体的列是jsonb.

我真的找不到一种方法来将数据解组到一个在proto上被定义为协议缓冲区的属性.

repeated google.protobuf.Any list = 1;

当我try 使用json.Unmarshal()对数据库中的数据进行解组时,则list为空.文档中提到了如下内容:

foo := &pb.Foo{...}
 any, err := anypb.New(foo)
 if err != nil {
   ...
 }
 ...
 foo := &pb.Foo{}
 if err := any.UnmarshalTo(foo); err != nil {
   ...
 }

但在这个例子中,fooproto.Message类型的,我不能转换,因为我有json.RawMessage.

我有什么办法可以做到这一点吗?

推荐答案

首先,您应该了解DB列中存储的内容.json.RawMessage被简单地定义为type RawMessage []byte(见the doc).而且它没有提供足够的信息来回答你的问题.

我将提供一个演示来展示google.protobuf.Any是如何工作的,这将帮助您更好地理解您的问题.

Notes:

  1. Any is for embedding other types in a message. So I define two other messages (Foo and Bar) in the demo.

    Any消息类型允许您将消息用作嵌入类型,而无需.proto定义.Any包含作为字节的任意序列化消息,以及充当该消息类型的全局唯一标识符并解析为该消息类型的URL.

  2. 实际上,您的问题取决于数据库中存储的内容.请参阅main.go中的 comments .

演示的文件夹 struct :

├── go.mod
├── main.go
└── pb
    ├── demo.pb.go
    └── demo.proto

go.mod:

module github.com/ZekeLu/demo

go 1.19

require (
    github.com/golang/protobuf v1.5.2
    google.golang.org/protobuf v1.28.1
)

pb/demo.proto:

syntax = "proto3";
package pb;

import "google/protobuf/any.proto";

option go_package = "github.com/ZekeLu/demo/pb";

message MyMessage {
  repeated google.protobuf.Any list = 1;
}

message Foo {
  int32 v = 1;
}

message Bar {
  string v = 1;
}

main.go:

package main

import (
    "encoding/json"
    "fmt"

    "google.golang.org/protobuf/types/known/anypb"

    "github.com/ZekeLu/demo/pb"
)

func main() {
    // If the db stores an instance of pb.Foo, then unmarshal it first.
    buf := json.RawMessage([]byte(`{"v":10}`))
    var foo pb.Foo
    err := json.Unmarshal(buf, &foo)
    if err != nil {
        panic(err)
    }

    // And then marshal it into a new Any instance, which can be used to
    // create a slice that can be assigned to pb.MyMessage.List.
    a1, err := anypb.New(&foo)
    if err != nil {
        panic(err)
    }

    bar := &pb.Bar{V: "10"}
    a2, err := anypb.New(bar)
    if err != nil {
        panic(err)
    }

    // Initialize the List field.
    m := pb.MyMessage{List: []*anypb.Any{a1, a2}}

    buf, err = json.Marshal(&m)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%s\n", buf)
    // Output: {"list":[{"type_url":"type.googleapis.com/pb.Foo","value":"CAo="},{"type_url":"type.googleapis.com/pb.Bar","value":"CgIxMA=="}]}

    // If the db stores the output above, it can be unmarshal directly
    var m2 pb.MyMessage
    err = json.Unmarshal(buf, &m2)
    if err != nil {
        panic(err)
    }

    fmt.Printf("%v\n", m2.List)
    // Output: [[type.googleapis.com/pb.Foo]:{v:10} [type.googleapis.com/pb.Bar]:{v:"10"}]
}

运行演示的步骤:

$ protoc --proto_path=pb --go_out=pb --go_opt=paths=source_relative demo.proto
$ go mod tidy
$ go run main.go

Go相关问答推荐

golang父进程的副本无法进行https/tls调用并获得tls:未能验证证书""

Go-Colly:将数据切片为POST请求

无法获取RPC描述符

Cypher 查找(多个)最低 node

这是go语言gin提供的关于TypeEngine和RouterGroup的问题

使用 OpenTelemetry 统一不同服务的范围

Golang chromedp Dockerfile

在VSCode中如何使用特定的文件名提供编译命令

同一文件上的多个 Arrow CSV 阅读器返回 null

有没有办法计算枚举中定义的项目总数?

使用 os/exec 和在命令行执行之间的结果莫名其妙地不同

Golang 通过接口反映/迭代{}

如何在 Golang 中使用具有相同名称或特定关键字的行或列重新排列/排序 CSV

Golang 使用 docker 将敏感数据作为参数传递

golang jwt.MapClaims 获取用户ID

是否可以使用按位运算在随机 unicode 字符串中找到重复字符?

函数的递归调用以 goroutine 和惯用方式开始,以在所有工作 goroutine 完成时继续调用者

Dynamodb.ScanInput - 不能使用expr.Names()(类型 map[string]*string)作为类型 map[string]string

如何发送带有登录数据的 GET 请求并将 cookie 数据保存到 txt 文件?

为什么在 unsafe.Sizeof() 中取消引用 nil 指针不会导致panic ?