SQLC – 如何检索存储为 JSONB 的数据

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

SQLC - how to retrieve data stored as JSONB

问题

我有一个简单的表格,其中有一个字段是JSONB:

CREATE TABLE IF NOT EXISTS "test_table" (
    "id" text NOT NULL,
    "user_id" text NOT NULL,
    "content" jsonb NOT NULL,
    "create_time" timestamptz NOT NULL,
    "update_time" timestamptz NOT NULL,
    PRIMARY KEY ("id")
);

我使用一个简单的查询来生成SQLC的样板代码:

-- name: GetTestData :one
SELECT * FROM test_table
WHERE id = $1 LIMIT 1;

但是content属性生成为json.RawMessage

type TestTable struct {
    ID          string          `json:"id"`
    UserId      string          `json:"user_id"`
    Content     json.RawMessage `json:"content"`
    CreateTime  time.Time       `json:"create_time"`
    UpdateTime  time.Time       `json:"update_time"`
}

这是存储在content列中的JSON的示例:

{
  "static": {
    "product": [
      {
        "id": "string",
        "elements": {
          "texts": [
            {
              "id": "string",
              "value": "string"
            }
          ],
          "colors": [
            {
              "id": "string",
              "value": "string"
            }
          ],
          "images": [
            {
              "id": "string",
              "values": [
                {
                  "id": "string",
                  "value": "string"
                }
              ]
            }
          ]
        }
      }
    ]
  },
  "dynamic": {
    "banner": [
      {
        "id": "string",
        "elements": {
          "texts": [
            {
              "id": "string",
              "value": "string"
            }
          ],
          "colors": [
            {
              "id": "string",
              "value": "string"
            }
          ],
          "images": [
            {
              "id": "string",
              "values": [
                {
                  "id": "string",
                  "value": "string"
                }
              ]
            }
          ]
        }
      }
    ]
  }
}

Static或Dynamic内部的嵌套属性是数组。

content属性应该包含一个嵌套对象,但我似乎无法提取其中的数据。json.Unmarshal()似乎只能获取顶层属性。是否有一种方法可以将map[string]interface{}转换为content,或者帮助SQLC将属性生成为接口而不是RawMessage?

我尝试解决这个问题,只需解组装载消息,如下所示:

var res map[string]json.RawMessage
if err := json.Unmarshal(testingData.Content, &res); err != nil {
    return nil, status.Errorf(codes.Internal, "Serving data err %s", err)
}

var static pb.Static
if err := json.Unmarshal(res["Static"], &static); err != nil {
    return nil, status.Errorf(codes.Internal, "Static data err %s", err)
}
var dynamic pb.Dynamic
if err := json.Unmarshal(res["Dynamic"], &dynamic); err != nil {
    return nil, status.Errorf(codes.Internal, "Dynamic data err %s", err)
}

在解组装载数据时,我做错了什么,但我无法确定具体是什么。

这是一个示例 playground:go.dev/play/p/9e7a63hNMEA

英文:

I have a simple table that has a field JSONB:

CREATE TABLE IF NOT EXISTS "test_table" (
    "id" text NOT NULL,
    "user_id" text NOT NULL,
    "content" jsonb NOT NULL,
    "create_time" timestamptz NOT NULL,
    "update_time" timestamptz NOT NULL,
    PRIMARY KEY ("id")
);

I used a simple query to generate boilerplate with SQLC.

-- name: GetTestData :one
SELECT * FROM test_table
WHERE id = $1 LIMIT 1;

But the content property gets generated as json.RawMessage.

type TestTable struct {
	ID          string          `json:"id"`
	UserId      string          `json:"user_id"`
	Content     json.RawMessage `json:"content"`
	CreateTime  time.Time       `json:"create_time"`
	UpdateTime  time.Time       `json:"update_time"`
}

Here's a sample of the JSON that is stored inside the content column:

{
  "static": {
    "product": [
      {
        "id": "string",
        "elements": {
          "texts": [
            {
              "id": "string",
              "value": "string"
            }
          ],
          "colors": [
            {
              "id": "string",
              "value": "string"
            }
          ],
          "images": [
            {
              "id": "string",
              "values": [
                {
                  "id": "string",
                  "value": "string"
                }
              ]
            }
          ]
        }
      }
    ]
  },
  "dynamic": {
    "banner": [
      {
        "id": "string",
        "elements": {
          "texts": [
            {
              "id": "string",
              "value": "string"
            }
          ],
          "colors": [
            {
              "id": "string",
              "value": "string"
            }
          ],
          "images": [
            {
              "id": "string",
              "values": [
                {
                  "id": "string",
                  "value": "string"
                }
              ]
            }
          ]
        }
      }
    ]
  }
}

Nested properties inside Static or Dynamic are arrays.

The content property should contain a nested object, and I can't seem to extract the data inside it. json.Unrmarshall() seems get only the top level properties. Is there a way to cast
map[string]interface{} to content or to help SQLC generate the property as interface instead of RawMessage?

I tried to solve this just unmarshalling the raw message like so:

var res map[string]json.RawMessage
if err := json.Unmarshal(testingData.Content, &res); err != nil {
	return nil, status.Errorf(codes.Internal, "Serving data err %s", err)
}

var static pb.Static
if err := json.Unmarshal(res["Static"], &static); err != nil {
	return nil, status.Errorf(codes.Internal, "Static data err %s", err)
}
var dynamic pb.Dynamic
if err := json.Unmarshal(res["Dynamic"], &dynamic); err != nil {
	return nil, status.Errorf(codes.Internal, "Dynamic data err %s", err)
}

I'm doing something wrong when unmarshalling the payload but I can't figure out what exactly.

Here's a sample playground: go.dev/play/p/9e7a63hNMEA

答案1

得分: 1

你的JSON包含staticdynamic键。你正在解析成map[string]json.RawMessage,然后尝试从map中获取StaticDynamic(注意大小写)。

修复map的键(例如json.Unmarshal(res["static"], &static)),你的代码可能会正常工作。一个更好的解决方案可能是在尝试解析之前检查键是否存在。

英文:

Your JSON contains static and dynamic keys. You are parsing into a map[string]json.RawMessage and then trying to retrieve Static and Dynamic from the map (note the capitalisation).

Fix the map keys (i.e. json.Unmarshal(res["static"], &static))and your code will probably work. A better solution might be to check if the keys exist before attempting to unmarshal them.

huangapple
  • 本文由 发表于 2022年10月31日 10:54:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/74258327.html
匿名

发表评论

匿名网友

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

确定