处理req.body数组数据实现关联表批量插入报错求助
问题描述
我有表a和表b,需要同时创建两类数据,表b以表a的id作为外键,要批量向表b插入多行数据。从req.body接收的数据格式如下:
{ "userId": 1, "a1": "ccc", "a2": "ddd", "typeId": [1, 2, 3], "count": [60, 100, 5] }
期望生成的SQL插入语句格式:
INSERT INTO data (a_id,typeId,count) VALUES (0,1,60), (0,2,100), (0,3,5)
我尝试了两段DAO代码,但都报错:
第一段代码及报错
const createRecordData = async(userId, a1, a2, typeId, count) => { await myDataSource.query( `INSERT INTO a (user_id,a1,a2) VALUES(?,?,?)`, [userId, a1, a2] ); const datas = await myDataSource.query( `INSERT INTO data (a_id,typeId,count) VALUES ${typeId.map((tID) =>"(" + "((SELECT 1939616)" + "," + tID + "," + count.map((c) => c + ")" ).join(","))}`, [typeId, count] ); return data; };
报错信息:
SyntaxError: Unexpected string in JSON at position 101
第二段代码及报错
const createRecordData = async(userId, a1, a2, typeId, count) => { await myDataSource.query( `INSERT INTO a (user_id,a1,a2) VALUES(?,?,?)`, [userId, a1, a2] ); const typeAndCount = typeId.map((type, index) => `((SELECT 1939616),${type},${count[index]}),`).join(""); const datas = await myDataSource.query( `INSERT INTO data (a_id,typeId,count) VALUES ${typeAndCount}`, [typeId, count] ); return data; };
报错信息:
"typeId.map is not a function"
错误分析及解决方法
1. 第二段代码报错原因
typeId.map is not a function说明typeId不是数组类型。大概率是调用createRecordData时参数传递错误——比如解构req.body时出错,或者传递了非数组值给typeId。
解决:检查函数调用处,确保正确传递数组参数:
const { userId, a1, a2, typeId, count } = req.body; await createRecordData(userId, a1, a2, typeId, count);
2. 第一段代码的SQL语法错误
拼接VALUES部分时逻辑混乱:内层count.map会把所有count值塞进每个typeId对应的括号,生成非法SQL结构(比如((SELECT 1939616),1,60),(100),(5))),触发JSON解析错误。
3. 通用问题:硬编码外键、SQL注入风险、未获取真实自增ID
- 硬编码
SELECT 1939616作为a_id,正确做法是插入表a后获取其自增id; - 直接拼接字符串生成SQL存在SQL注入风险,必须用参数化查询;
- 函数返回值错误(返回未定义的
data,应为datas)。
正确实现代码
const createRecordData = async(userId, a1, a2, typeId, count) => { // 校验数组长度一致 if (typeId.length !== count.length) { throw new Error('typeId和count数组长度不匹配'); } // 插入表a并获取自增id(不同数据库获取方式:MySQL用insertId,PostgreSQL用returning) const [insertAResult] = await myDataSource.query( `INSERT INTO a (user_id,a1,a2) VALUES(?,?,?)`, [userId, a1, a2] ); const aId = insertAResult.insertId; // 生成参数化占位符和参数数组 const placeholders = typeId.map(() => "(?,?,?)").join(","); const params = []; typeId.forEach((type, index) => { params.push(aId, type, count[index]); }); // 执行批量插入 const datas = await myDataSource.query( `INSERT INTO data (a_id,typeId,count) VALUES ${placeholders}`, params ); return datas; };
关键优化点
- 获取表a真实自增id作为外键,避免硬编码;
- 使用参数化占位符
?生成SQL,彻底规避SQL注入; - 增加数组长度校验,避免数据不匹配;
- 修复返回值错误。
内容的提问来源于stack exchange,提问作者ggyoE
相关产品推荐
相关产品推荐

