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

基于Postgres、Knex/Express的批量更新及历史记录追加问题

如何在Knex中批量向JSON数组字段追加新记录

你已经实现了资产状态和位置的批量更新逻辑,现在要在不覆盖原有数据的前提下,向history JSON数组字段追加新操作记录,以下是针对不同数据库的解决方案:

针对PostgreSQL(你的代码中使用了->>操作符,推测是PostgreSQL)

PostgreSQL支持直接通过||操作符向JSONB数组追加元素,同时用COALESCE处理字段为null的情况(自动转为空数组)。修改后的代码如下:

async function bulkUpdate(req, res){
  const site = req.body.data;
  // 构造新的操作记录,根据实际业务填充字段值
  const newHistoryEntry = {
    action_date: new Date().toISOString(),
    action_taken: "Pending Transfer",
    action_by: req.user?.name || "Unknown", // 从请求上下文获取操作人
    action_by_id: req.user?.id || 0,
    action_comment: `批量更新站点状态为待转移:${site.physical_site_name}`,
    action_key: require('uuid').v4() // 生成唯一操作标识(需先安装uuid库)
  };

  const data = await knex('assets')
    // 修复SQL注入风险:用参数绑定替代字符串拼接
    .whereRaw(`location ->> 'site' = ?`, [site.physical_site_name])
    .update({ 
      status: "Pending Transfer",
      location: { 
        site: site.physical_site_name, 
        site_loc: { first_octet: site.first_octet, mdc: '', shelf: '', unit: ''}
      },
      // 追加新记录到history数组,处理null情况
      history: knex.raw(`COALESCE(history, '[]'::jsonb) || ?::jsonb`, [newHistoryEntry])
    })
    .returning('*')
    .then(results => results[0]);

  res.status(200).json({ data });
}

关键说明:

  • 防SQL注入:原代码中直接拼接字符串到whereRaw存在注入风险,改为参数绑定?后Knex会自动处理转义
  • 处理null值:COALESCE(history, '[]'::jsonb)确保当history为null时,先转为空数组再追加新元素
  • JSONB类型:确保history字段在PostgreSQL中是jsonb类型(比json更适合更新操作)

针对MySQL

如果使用MySQL,需要用JSON_ARRAY_APPEND函数,同时用IFNULL处理空值:

// 替换update中的history字段更新逻辑
history: knex.raw(`JSON_ARRAY_APPEND(IFNULL(history, '[]'), '$', ?)`, [newHistoryEntry])

注意事项:

  • MySQL中history字段需设为json类型
  • JSON_ARRAY_APPEND的'$'参数表示向数组根节点追加元素

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 02:05:24