英文:
Unmarshal protojson formatted Firestore cloud event into map[string]interface{} or struct
问题
有没有一种简单的方法可以将以 protojson 格式表示的 Firestore 数据解组成 map[string]interface{} 或结构体,而不需要所有的 protobuf 数据类型标签?即将 protojson 数据展开。
我有一个 Google Cloud 函数,每当创建一个新的 Firebase 文档时触发(称为“云事件”)。这个云事件包括上下文信息,包括以 protojson 格式修改的文档:
import (
"google.golang.org/protobuf/encoding/protojson"
"github.com/davecgh/go-spew/spew"
)
func CloudFunction(ctx context.Context, e event.Event) error {
data := firestoredata.DocumentEventData{}
_ = protojson.Unmarshal(e.DataEncoded, &data)
spew.Dump(data)
}
--------控制台输出--------
{
"oldValue": {},
"value": {
"createTime": "2023-03-30T00:00:00.000000Z",
"updateTime": "2023-03-30T00:00:00.000000Z",
"name": "projects/myproject/databases/(default)/documents/collectionname/00000000-0000-0000-0000-000000000000",
"fields": {
"ID": {
"stringValue": "00000000-0000-0000-0000-000000000000"
},
"action": {
"stringValue": "serverDoSomething"
},
"payload": {
"mapValue": {
"fields": {
"questionsList": {
"arrayValue": {
"values": [
{
"mapValue": {
"fields": {
"title": {
"stringValue": "How do I fly a kite?"
}
}
}
},
{
"mapValue": {
"fields": {
"title": {
"stringValue": "How do I fly a plane?"
}
}
}
}
]
}
}
}
}
}
}
},
"updateMask": {}
}
我想将这个 protojson 文档的各个部分解组成自定义的 Go 结构体,以便轻松验证每种类型的条目,如下所示:
// CloudEventRequest 是一个包装一个或多个数据验证结构体的结构体,这些结构体包含在 payload 中
CloudEventRequest {
ID: "00000000-0000-0000-0000-000000000000",
Action: "serverDoStuff",
Payload: map{
"questionsList": []Question{
Question{
Title: "How do I fly a kite?"
},
Question{
Title: "How do I fly a plane?"
}
}
}
}
Firestore SDK 包含一个 DataTo 方法,可以将 protojson 格式的数据轻松解组成自定义的结构体。我正在尝试做类似的事情,但已经在 Firestore SDK 之外获取了文档数据。
// DataTo 使用文档的字段填充 p,p 可以是指向 map[string]interface{} 或结构体的指针。
func (*firestore.DocumentSnapshot).DataTo(p interface{}) error
import (
"context"
"cloud.google.com/go/firestore"
)
func FirestoreRead(docEvent firestoredata.DocumentEventData) error {
ctx := context.Background()
ref := h.client.Collection("mycollection").Doc(docEvent.value.ID)
docSnapshot, err := tx.Get(ref)
dataValidationStruct := CloudEventRequest{}
err = docSnapshot.DataTo(&dataValidationStruct)
}
英文:
Is there an easy way to unmarshal Firestore data in protojson format into a map[string]interface{} or struct without all the protobuf data type tags? i.e. flatten the protojson data.
I have a Google cloud function that's triggered whenever a new Firebase document is created (a "cloud event"). This cloud event includes context information including the document being modified in protojson format:
import (
"google.golang.org/protobuf/encoding/protojson"
"github.com/davecgh/go-spew/spew"
)
func CloudFunction(ctx context.Context, e event.Event) error {
data := firestoredata.DocumentEventData{}
_ = protojson.Unmarshal(e.DataEncoded, &data);
spew.Dump(data)
}
--------Console Output--------
{
"oldValue": {},
"value": {
"createTime": "2023-03-30T00:00:00.000000Z",
"updateTime": "2023-03-30T00:00:00.000000Z",
"name": "projects/myproject/databases/(default)/documents/collectionname/00000000-0000-0000-0000-000000000000",
"fields": {
"ID": {
"stringValue": "00000000-0000-0000-0000-000000000000"
},
"action": {
"stringValue": "serverDoSomething"
},
"payload": {
"mapValue": {
"fields": {
"questionsList": {
"arrayValue": {
"values": [
{
"mapValue": {
"fields": {
"title": {
"stringValue": "How do I fly a kite?"
},
}
}
},
{
"mapValue": {
"fields": {
"title": {
"stringValue": "How do I fly a plane?"
},
}
}
}
]
}
}
}
}
}
}
},
"updateMask": {}
}
I want to marshal chunks of this protojson document into custom Go structs to easily validate each type of entry as shown below:
// CloudEventRequest is a struct that wraps around one or more data validation structs contained in the payload
CloudEventRequest {
ID: "00000000-0000-0000-0000-000000000000"
Action: "serverDoStuff"
Payload: map{
"questionsList": []Question{
Question{
Title: "How do I fly a kite?"
},
Question{
Title: "How do I fly a plane?"
}
}
}
}
The Firestore SDK includes a DataTo method to easily unmarshal the protojson formatted data into custom structs. I'm trying to do something very similar but already obtained the document data outside of the Firestore SDK.
// DataTo uses the document's fields to populate p, which can be a pointer to a map[string]interface{} or a pointer to a struct.
func (*firestore.DocumentSnapshot).DataTo(p interface{}) error
import (
"context"
"cloud.google.com/go/firestore"
)
func FirestoreRead(docEvent firestoredata.DocumentEventData) error {
ctx := context.Background()
ref := h.client.Collection("mycollection").Doc(docEvent.value.ID)
docSnapshot, err := tx.Get(ref)
dataValidationStruct := CloudEventRequest{}
err = docSnapshot.DataTo(&dataValidationStruct)
}
答案1
得分: 0
我写了一个名为"firestruct"的开源Go包来解决这个问题。你可以在这里找到它:github.com/bennovw/firestruct
欢迎你提供反馈和贡献!
我最终编写了一个递归解包Firestore字段并将其转换为匹配的映射的函数。然后,我重构了cloud.google.com/go/firestore中的DataTo()方法,将我的映射解组为一个结构体。
英文:
I wrote an open source Go package named "firestruct" to solve this challenge. You can find it here: github.com/bennovw/firestruct
Your feedback and contributions are most welcome!
I ended up writing a function that recursively unwraps Firestore fields into a matching map. I then refactored the DataTo() method in cloud.google.com/go/firestore to unmarshal my map into a struct.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论