mysql 更新json字段

// 路由

router.get("/winner", async function (req, res, next) {
  let id = Number(req.query.id);
  let fileUrlId = req.query.fileUrlId;

  if (!id && !fileUrlId) {
    return res.send(failModel(2004, false, null));
  }

  const resGetWC = await getCurrentFileUrl(id);
  if (resGetWC.length === 1) {
    const tempFileUrl = JSON.parse(resGetWC[0].fileUrl).reduce(
      (result, item) => {
        if (item.id === fileUrlId) {
          item.winnerCount
            ? (item.winnerCount = item.winnerCount + 1)
            : (item.winnerCount = 1);
        }
        result.push(item);
        return result;
      },
      []
    );


    const resultUpdate = await updateWinner(
      id,
      JSON.stringify(tempFileUrl)
    );

    if (resultUpdate?.affectedRows === 1) {
      return res.send(successModel());
    }
    return res.send(failModel(-1, false, null));
  }

  return res.send(failModel(-1, false, null));
});


// updateWinner

const updateWinner = async (id, fileUrl) => {
    const resultGet = await getCurrentWinnerCount(id);
    if (resultGet.length === 1) {
      const sql = `
      UPDATE vs_make_lists
      SET fileUrl = ${escapeSqlString(fileUrl)}, winnerCount ='${
        resultGet[0].winnerCount ? resultGet[0].winnerCount + 1 : 1
      }'
      WHERE list_id = ${id}
    `;
  
      return execSQL(sql);
    }
  
    return;
  };

  const escapeSqlString = str => {
    return mysql.escape(str);
  };

问题:

  1. 解析JSON JSON.parse(resGetWC[0].fileUrl)
  2. 使用reduce 添加winnerCount 字段
  3. 调用updateWinner 传JSON.stringify(tempFileUrl)
  4. 插入数据库的时候该 fileUrl JSON字段并没有包含 winnerCunt字段
  5. 再次调用的时候 fileUrl JSON字段中包含 winnerCunt字段

本地数据库是没有复现出来的,线上的时候会出现此问题

从你的描述,本地数据库可以正常工作,线上数据库在更新 JSON 字段的时候出现问题,原因主要有两点:

  1. 数据库引擎对 JSON 字段的支持程度不同。不同的数据库对 JSON 字段的支持程度会不同,可能导致某些操作无法正常执行。
  2. 逃逸字符问题。由于 JSON 字符串中可能包含一些特殊字符,如 ", ', , 等,这可能导致 SQL 语句错误。
    解决方案:
  3. 检查数据库引擎对 JSON 的支持。可以参考官方文档,确认所使用的数据库对 JSON 支持足够。如果不支持,可以考虑更换数据库或使用其他方式存储数据。
  4. 对 JSON 字符串进行转义。在插入或更新 JSON 字符串前,使用数据库的 escape 或 quote 函数对其进行转义,避免 SQL 注入等问题。
    例如:
    MySQL:
    sql
    UPDATE table
    SET json_col = JSON_QUOTE(json_string)
    PostgreSQL:
    sql
    UPDATE table
    SET json_col = $#{ json_string }#$
    所以,我的解决方案是:
  5. 在调用 JSON.stringify() 将对象序列化为 JSON 字符串前,检查数据库是否支持 JSON 及相关操作。如果不支持,考虑其他解决方案。
  6. 在插入或更新 JSON 字段前,使用 escapeSqlString() 函数对 JSON 字符串进行转义,然后再执行 SQL 语句。
    escapeSqlString() 函数示例:
    js
    const escapeSqlString = str => {
    return mysql.escape(str);
    }
    然后在调用 execSQL() 执行 SQL 语句前,使用转义后的 JSON 字符串:
    js
    const sql = UPDATE vs_make_lists SET fileUrl = ${escapeSqlString(JSON.stringify(tempFileUrl))}
    execSQL(sql);
    希望这能帮助你解决问题。如果有任何其他疑问,欢迎在回复中提出。
    你的提出的两点解决方案:
  7. 检查数据库引擎对 JSON 的支持。
    我使用的数据库是mysql,mysql是支持json类型的,并且我本地测试是没有问题的。所以主要还是第二点。
  8. 对 JSON 字符串进行转义。
    这点我在代码中并没有注意到,直接拼接了JSON.stringify(tempFileUrl)。这点应该是我代码的漏洞。
    你提供的示例代码:
    js
    const escapeSqlString = str => {
    return mysql.escape(str);
    }

const sql = UPDATE vs_make_lists SET fileUrl = ${escapeSqlString(JSON.stringify(tempFileUrl))}
execSQL(sql);
这段代码对我很有帮助,我会按照你的建议修改我的代码,转义JSON字符串后再更新到数据库。
非常感谢你的反馈和提出的建议解决方案。这对我理解问题和提高编码意识很有帮助。
我会将你的解答和建议记录下来,以后遇到类似的问题可以参考。
再次感谢!
你提到的两点,一是检查数据库支持度,二是字符串转义,这两个点在操作数据库时非常重要,容易出现问题。记录并理解这两个点,对你以后处理数据库非常有好处。

直接使用MYSQL自带的JSON函数处理