PostgreSQL jsonb 更新多个嵌套字段
PostgreSQL jsonb update multiple nested fields
我 table 在 postgresql 数据库中有一个 id
字段和一个 jsonb
字段。 jsonb 的结构看起来像这样:
{
"id": "some-id",
"lastUpdated": "2018-10-24T10:36:29.174Z",
"counters": {
"counter1": 100,
"counter2": 200
}
}
我需要做的是更新 lastModified
和其中一个计数器:
def update(id: String, counter: Option[String])
例如,如果我做 update("some-id", Some("counter2"))
,我需要 lastUpdated
作为当前日期时间,counter2
增加到 201
。
我正在使用 ScalikeJDBC,这是我到目前为止的进展:
def update(id: String, counter: Option[String]): Option[ApiKey] = DB localTx { implicit session =>
val update =
if(counter.isDefined)
sqls"""'{"lastUpdated": ${DateTime.now()}, "counters": {'${counter.get}: COALESCE('counters'->>${counter.get},'0')::int'}'"""
else
sqls"""'{"lastUpdated": ${DateTime.now()}}'"""
sql"UPDATE apiKey SET content = content || $update WHERE id = $key".update().apply()
}
但是我得到以下错误:
org.postgresql.util.PSQLException: The column index is out of range: 4, number of columns: 3
我尝试过其他方法,但我无法使其发挥作用。是否可以将其写为单个查询?
这里有一个损坏的 fiddle 可以帮助测试 https://www.db-fiddle.com/f/bsteTUMXDGDSHp32fw2Zop/1
我不太了解 PostgreSQL 的 jsonb
类型,但似乎不可能在 JDBC PreparedStatement 中将所有内容都作为绑定参数传递。我不得不说,您可能必须使用 SQLSyntax.createUnsafely 来绕过 PreparedStatement,如下所示:
def update(id: String, counter: Option[String]): Unit = DB localTx { implicit session =>
val now = java.time.ZonedDateTime.now.toOffsetDateTime.toString
val q: SQLSyntax = counter match {
case Some(c) =>
val content: String =
s"""
jsonb_set(
content || '{"lastUsed": "${now}"}',
'{counters, $c}',
(COALESCE(content->'counters'->>'$c','0')::int + 1)::text::jsonb
)
"""
SQLSyntax.createUnsafely(s"""
UPDATE
example
SET
content = ${content}
WHERE
id = '$id';
""")
case _ =>
throw new RuntimeException
}
sql"$q".update.apply()
}
update("73c1fa11-bf2f-42c9-80fd-c70ac123fca9", Some("counter2"))
我 table 在 postgresql 数据库中有一个 id
字段和一个 jsonb
字段。 jsonb 的结构看起来像这样:
{
"id": "some-id",
"lastUpdated": "2018-10-24T10:36:29.174Z",
"counters": {
"counter1": 100,
"counter2": 200
}
}
我需要做的是更新 lastModified
和其中一个计数器:
def update(id: String, counter: Option[String])
例如,如果我做 update("some-id", Some("counter2"))
,我需要 lastUpdated
作为当前日期时间,counter2
增加到 201
。
我正在使用 ScalikeJDBC,这是我到目前为止的进展:
def update(id: String, counter: Option[String]): Option[ApiKey] = DB localTx { implicit session =>
val update =
if(counter.isDefined)
sqls"""'{"lastUpdated": ${DateTime.now()}, "counters": {'${counter.get}: COALESCE('counters'->>${counter.get},'0')::int'}'"""
else
sqls"""'{"lastUpdated": ${DateTime.now()}}'"""
sql"UPDATE apiKey SET content = content || $update WHERE id = $key".update().apply()
}
但是我得到以下错误:
org.postgresql.util.PSQLException: The column index is out of range: 4, number of columns: 3
我尝试过其他方法,但我无法使其发挥作用。是否可以将其写为单个查询?
这里有一个损坏的 fiddle 可以帮助测试 https://www.db-fiddle.com/f/bsteTUMXDGDSHp32fw2Zop/1
我不太了解 PostgreSQL 的 jsonb
类型,但似乎不可能在 JDBC PreparedStatement 中将所有内容都作为绑定参数传递。我不得不说,您可能必须使用 SQLSyntax.createUnsafely 来绕过 PreparedStatement,如下所示:
def update(id: String, counter: Option[String]): Unit = DB localTx { implicit session =>
val now = java.time.ZonedDateTime.now.toOffsetDateTime.toString
val q: SQLSyntax = counter match {
case Some(c) =>
val content: String =
s"""
jsonb_set(
content || '{"lastUsed": "${now}"}',
'{counters, $c}',
(COALESCE(content->'counters'->>'$c','0')::int + 1)::text::jsonb
)
"""
SQLSyntax.createUnsafely(s"""
UPDATE
example
SET
content = ${content}
WHERE
id = '$id';
""")
case _ =>
throw new RuntimeException
}
sql"$q".update.apply()
}
update("73c1fa11-bf2f-42c9-80fd-c70ac123fca9", Some("counter2"))