注意:我只用 MySQL 测试过这个问题。
使用 bool 参数查询 json 字段内的属性时,查询返回 0 行。但是,如果将 bool 嵌入到 where 子句本身,则会得到 1 行。奇怪的是,调试器显示的生成的 SQL 是相同的。
下面的
results
属于 []Account
类型:
type Account struct {
gorm.Model
UserID sql.NullInt64
Number string
Config AccountConfig `gorm:"type:json;serializer:json"`
}
type AccountConfig struct {
Enabled bool `json:"enabled"`
Foo string `json:"foo"`
Bar int64 `json:"bar"`
}
损坏的示例:
DB.Where("config->'enabled' = ?", true).Find(&results)
2024/04/30 11:20:10 /__REDACTED__/playground/main_test.go:108
[0.847ms] [rows:0] SELECT * FROM `accounts` WHERE config->'$.enabled' = true
工作示例:
DB.Where("config->'enabled' = true").Find(&results)
2024/04/30 11:20:10 /__REDACTED__/playground/main_test.go:108
[0.647ms] [rows:1] SELECT * FROM `accounts` WHERE config->'$.enabled' = true
我还尝试测试各种其他变体,例如使用
json_extract
和双箭头语法,如 config->>'$.enabled'
。嵌套值也会发生同样的情况,例如 config->'$.foo.enabled' = true
。
另外,请参阅 GORM 存储库中的我在 github 上的问题。我在问题中链接的我的拉取请求中提供了一系列测试用例。
在 MySQL 中,JSON 文档中的布尔字段以标量 JSON 文档或标量字符串值的形式返回。您可以使用 mysql 客户端的
--column-type-info
选项看到这一点:
$ mysql --column-type-info
使用
->
返回 JSON 文档,即使该 JSON 文档仅包含单个标量值。
mysql> select config->'$.enabled' from Accounts;
Field 1: `config->'$.enabled'`
Catalog: `def`
Database: ``
Table: ``
Org_table: ``
Type: JSON
Collation: utf8mb4_0900_ai_ci (255)
Length: 4294967292
Max_length: 4
Decimals: 31
Flags: BINARY
+---------------------+
| config->'$.enabled' |
+---------------------+
| true |
+---------------------+
使用
->>
返回一个“不带引号”的值,它将 JSON 值转换为二进制字符串。
mysql> select config->>'$.enabled' from Accounts;
Field 1: `config->>'$.enabled'`
Catalog: `def`
Database: ``
Table: ``
Org_table: ``
Type: LONG_BLOB
Collation: utf8mb4_0900_ai_ci (255)
Length: 4294967295
Max_length: 4
Decimals: 31
Flags: BINARY
+----------------------+
| config->>'$.enabled' |
+----------------------+
| true |
+----------------------+
无论哪种方式,从 JSON 中提取布尔值的结果都不会产生 SQL 布尔值,因此它无法与
true
或 Go 布尔值 true
进行比较。
我让它以这种方式工作:
db.Where("config->>'$.enabled' = ?", "true").Find(&results)
因此,我传递 Go string 值
"true"
,它将与从 JSON 提取运算符返回的 SQL 二进制字符串 'true'
进行比较。
我强烈建议您使用普通列而不是 JSON。使用 JSON 没有什么优势,而且它引入了很多奇怪的复杂性,就像这个例子一样。