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

如何从JSON API请求向SQL Server表批量插入多条记录(API接收JSON数组异常问题解决)

嘿,我一眼就看出问题出在哪了——你的API当前只能处理单个JSON对象的插入请求,但你传入的是一个JSON数组。当你把数组塞进req.body后,let proof = { ...req.body }会把整个数组当成一个单独的对象,而这个数组对象根本没有proofID、client这些属性,所以传给存储过程的参数全是undefined,最终数据库里就只能插入null值,也就只有自增ID是正常生成的。

接下来给你两种解决方案,你可以根据自己的需求选择:


方案1:快速适配数组(循环调用现有存储过程)

这种方式不用修改SQL代码,只需要调整Node.js逻辑,适合快速上线或者数据量不大的场景。

1. 修正API端点的处理逻辑

原来的端点只处理单个对象,现在要判断请求体是数组还是单个对象,同时把回调改成async/await,避免循环里的异步操作乱序:

app.post('/api/proofs', limiter, async (req,res) => {
  try {
    const results = [];
    // 判断请求体是否为数组
    if (Array.isArray(req.body)) {
      // 遍历数组中的每一条数据
      for (const proofItem of req.body) {
        const insertResult = await dboperations.addProof(proofItem);
        results.push(...insertResult.recordsets[0]); // 把插入的记录直接存入结果数组
      }
    } else {
      // 处理单个对象的情况
      const insertResult = await dboperations.addProof(req.body);
      results.push(...insertResult.recordsets[0]);
    }
    res.status(201).json(results);
  } catch (error) {
    console.error('插入失败:', error);
    res.status(500).json({ message: '插入数据时发生错误' });
  }
})

2. 给addProof函数增加输入防护

避免传入无效对象导致报错,同时处理属性为undefined的情况:

async function addProof(proof){
  // 校验输入是否合法
  if (!proof || typeof proof !== 'object') {
    throw new Error('传入的proof数据格式无效');
  }
  try{
    const pool = await sql.connect(configJobData);
    const insertProof = await pool.request()
      // 用空值合并运算符,把undefined转成null传给SQL
      .input('proofID', sql.Int, proof.proofID ?? null)
      .input('runSeq', sql.Int, proof.runSeq ?? null)
      .input('client', sql.VarChar, proof.client ?? null)
      .input('result', sql.VarChar, proof.result ?? null)
      .execute('insertProof');
    return insertProof;
  } catch (error){
    console.error('存储过程调用失败:', error);
    throw error; // 把错误抛给上层处理
  }
}

方案2:高效批量插入(用SQL表值参数,推荐)

如果你的数据量较大,循环调用存储过程会有性能瓶颈,这时候用SQL Server的表值参数一次性插入所有数据是更优的选择。

1. 在SQL Server创建表值类型

执行以下脚本,创建一个和Proofs表结构匹配的自定义表类型:

USE [JobData2]
GO
CREATE TYPE [dbo].[ProofTableType] AS TABLE(
    [proofID] int NULL,
    [runSeq] int NULL,
    [client] varchar(75) NULL,
    [result] varchar(15) NULL
)
GO

2. 修改存储过程,支持批量插入

可以替换原有的insertProof,或者新建一个批量插入的存储过程:

ALTER PROCEDURE [dbo].[insertProofBatch]
    @Proofs [dbo].[ProofTableType] READONLY
AS
BEGIN
    SET NOCOUNT ON;
    -- 从表值参数中读取数据插入目标表
    INSERT INTO JobData2.dbo.Proofs (proofID,runSeq,client,result)
    OUTPUT Inserted.[ID], Inserted.[proofID], Inserted.[client], Inserted.[runSeq], Inserted.[result]
    SELECT proofID, runSeq, client, result FROM @Proofs
END
GO

3. 在Node.js中添加批量插入函数

修改dboperations.js,新增处理批量插入的方法:

async function addProofBatch(proofsArray){
  // 校验输入是否为非空数组
  if (!Array.isArray(proofsArray) || proofsArray.length === 0) {
    throw new Error('需要传入非空的proof数组');
  }
  try{
    const pool = await sql.connect(configJobData);
    // 创建与表值类型匹配的SQL表对象
    const table = new sql.Table();
    table.columns.add('proofID', sql.Int, { nullable: true });
    table.columns.add('runSeq', sql.Int, { nullable: true });
    table.columns.add('client', sql.VarChar(75), { nullable: true });
    table.columns.add('result', sql.VarChar(15), { nullable: true });

    // 将数组中的每条数据添加到SQL表中
    proofsArray.forEach(proof => {
      table.rows.add(proof.proofID, proof.runSeq, proof.client, proof.result);
    });

    // 调用批量插入存储过程
    const insertResult = await pool.request()
      .input('Proofs', table)
      .execute('insertProofBatch');
    return insertResult.recordsets[0];
  } catch (error){
    console.error('批量插入失败:', error);
    throw error;
  }
}

// 导出新函数
module.exports = { 
  addProof: addProof, 
  addProofBatch: addProofBatch 
}

4. 更新API端点逻辑

现在可以同时支持单个对象和数组的批量插入:

app.post('/api/proofs', limiter, async (req,res) => {
  try {
    let results;
    if (Array.isArray(req.body)) {
      // 数组请求使用批量插入
      results = await dboperations.addProofBatch(req.body);
    } else {
      // 单个对象使用原插入方法
      const singleResult = await dboperations.addProof(req.body);
      results = singleResult.recordsets[0];
    }
    res.status(201).json(results);
  } catch (error) {
    console.error('插入失败:', error);
    res.status(500).json({ message: '插入数据时发生错误' });
  }
})

现在用Postman测试你原来的JSON数组请求,应该就能得到两条完整的插入记录了,每个字段都有你传入的值,再也不会出现全null的情况啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 21:22:30