You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL JSONB:如何更新嵌套对象中的数组属性?

问题描述

我尝试更新PostgreSQL的jsonb字段中嵌套数组内对象的cleaner属性,但执行SQL后返回null且没有任何更新操作。需求是根据schedule的id值,更新对应项里的cleaner对象。

表结构

id(serial) | info(jsonb)

server.js 代码片段

var contractorInfo = {
    "id": cleanerid,
    "fname": fname,
    "lname": lname,
    "avatar": avatar
}

// 目标schedule的id
var laveid = 'order_cbs1l';

执行后无更新且返回null的SQL语句

UPDATE users SET info = JSONB_SET(info, '{schedule,cleaner}', '"+JSON.stringify(contractorInfo)+"') WHERE info->'schedule'->>'id'='"+laveid+"' RETURNING*
UPDATE users SET info = JSONB_SET(info, '{schedule,cleaner}', '"+JSON.stringify(contractorInfo)+"') WHERE info #>> '{schedule,id}' = '"+laveid+"' RETURNING*

示例JSON数据

{
  "dob": "1988-12-11",
  "type": "seller",
  "email": "johndoe@gmail.com",
  "phone": "5553766962",
  "avatar": "image.png",
  "schedule": [
    {
      "id": "order_cbs1l",
      "pay": "230",
      "date": "2022-12-29",
      "status": "Available",
      "address": "234 Eleventh Street, Mildura Victoria 3500, Australia",
      "cleaner": {
        "id": "",
        "fname": "",
        "lname": "",
        "avatar": ""
      },
      "end_time": "10:15",
      "start_time": "01:00",
      "total_hours": "33300000",
      "paymentIntentId": "pi_3KJnrEFzZWeJoxzV1yUdGLQ8"
    }
  ],
  "last_name": "doe",
  "first_name": "john",
  "countrycode": "Canada: +1",
  "countryflag": "iti__ca",
  "date_created": "2022-11-12T19:44:36.714Z"
}
解决方案

问题核心在于schedule是数组而非单个对象,之前的SQL既没有定位到数组中具体元素的索引,WHERE条件的写法也错误——直接访问info->'schedule'->>'id'是操作整个数组,无法匹配到数组内对象的id值。

正确写法(推荐参数化查询防注入)

在Node.js中不要直接拼接SQL字符串,改用参数化查询:

const query = `
  UPDATE users 
  SET info = jsonb_set(
    info,
    array['schedule', (idx - 1)::text, 'cleaner'],
    $1::jsonb
  )
  FROM (
    SELECT id, jsonb_array_elements(info->'schedule') WITH ORDINALITY AS s(sched, idx)
    FROM users
    WHERE s.sched->>'id' = $2
  ) AS sub
  WHERE users.id = sub.id
  RETURNING *;
`;

// 执行参数化查询
client.query(query, [contractorInfo, laveid], (err, res) => {
  if (err) throw err;
  console.log(res.rows);
});

逻辑说明

  1. 子查询定位数组元素:通过jsonb_array_elements(info->'schedule') WITH ORDINALITY遍历schedule数组,获取每个元素及其索引(idx),筛选出id匹配的目标元素。
  2. jsonb_set路径修正:数组索引从0开始,所以用idx-1转换为JSON路径的索引,完整路径为['schedule', 索引位置, 'cleaner']。
  3. 参数化查询:直接传入contractorInfo(pg客户端会自动转为jsonb)和laveid,彻底避免SQL注入风险。

临时字符串拼接写法(不推荐生产环境使用)

如果必须用字符串拼接,修正后的SQL如下:

UPDATE users 
SET info = jsonb_set(
  info,
  array['schedule', (idx - 1)::text, 'cleaner'],
  '${JSON.stringify(contractorInfo)}'::jsonb
)
FROM (
  SELECT id, jsonb_array_elements(info->'schedule') WITH ORDINALITY AS s(sched, idx)
  FROM users
  WHERE s.sched->>'id' = '${laveid}'
) AS sub
WHERE users.id = sub.id
RETURNING *;

内容的提问来源于stack exchange,提问作者Grogu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 19:10:32