将 protojson 格式的 Firestore 云事件解析为 map[string]interface{} 或 struct。

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

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.

huangapple
  • 本文由 发表于 2023年4月1日 00:30:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/75900791.html
匿名

发表评论

匿名网友

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

确定