如何遍历POST请求中多个JSON对象并赋值给变量完成入库操作
实现方案与优化建议
1. 正确获取POST提交的JSON数组
首先确保你的Express服务已经配置了JSON解析中间件(一般在入口文件中配置):
app.use(express.json())
配置完成后,客户端提交的JSON数组会直接被解析到req.body中,你直接赋值即可,还可以增加一层兼容逻辑,同时支持提交单个对象和数组场景:
// 直接从req.body获取,兼容单对象/数组提交 const battleList = Array.isArray(req.body) ? req.body : [req.body];
你之前尝试的解构写法是针对单个对象提交的场景,提交数组时不需要提前解构,遍历的时候单独处理每个对象即可。
2. 现有代码可优化的点
你现在写的遍历逻辑可以正常运行,但存在几个可优化的问题:
- 用
for...in遍历数组不符合规范,可能遍历到数组上挂载的非索引自定义属性,建议改用for...of遍历数组 - 串行
await插入数据,数据量较大时接口响应慢,可改用Promise.all并行插入提升效率 - 构造函数传参太多,很容易写错参数顺序,可改为直接传入整个对象减少冗余代码
- 直接拼接SQL语句存在SQL注入风险,建议改为参数化查询
3. 优化后完整代码示例
3.1 改造PostBattle类
class PostBattle { // 构造函数直接接收单条对战数据对象,不用逐个传参 constructor(battle) { // 批量赋值属性,减少重复代码 Object.assign(this, battle); // 单独处理需要序列化的技能字段 for (let i = 1; i <= 6; i++) { this[`monster_${i}_abilities`] = JSON.stringify(battle[`monster_${i}_abilities`] || '') } } async save() { // 改用参数化查询,避免SQL注入 const sql = ` INSERT INTO history ( summoner_id, summoner_level, monster_1_id, monster_1_level, monster_1_abilities, monster_2_id, monster_2_level, monster_2_abilities, monster_3_id, monster_3_level, monster_3_abilities, monster_4_id, monster_4_level, monster_4_abilities, monster_5_id, monster_5_level, monster_5_abilities, monster_6_id, monster_6_level, monster_6_abilities, created_date, match_type, mana_cap, ruleset, inactive, battle_queue_id, player_rating_initial, player_rating_final, winner ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ` // 按顺序拼接参数 const params = [ this.summoner_id, this.summoner_level, this.monster_1_id, this.monster_1_level, this.monster_1_abilities, this.monster_2_id, this.monster_2_level, this.monster_2_abilities, this.monster_3_id, this.monster_3_level, this.monster_3_abilities, this.monster_4_id, this.monster_4_level, this.monster_4_abilities, this.monster_5_id, this.monster_5_level, this.monster_5_abilities, this.monster_6_id, this.monster_6_level, this.monster_6_abilities, this.created_date, this.match_type, this.mana_cap, this.ruleset, this.inactive, this.battle_queue_id, this.player_rating_initial, this.player_rating_final, this.winner ] const [newPost, _] = await db.execute(sql, params) return newPost } }
3.2 改造接口逻辑
exports.createNewPost = async (req, res, next) => { try { // 获取对战列表,兼容单对象/数组提交 const battleList = Array.isArray(req.body) ? req.body : [req.body] // 并行生成实例+入库,效率更高 const savePromises = battleList.map(battle => { const post = new PostBattle(battle) return post.save() }) const result = await Promise.all(savePromises) console.log(`成功插入${result.length}条对战记录`) // 返回成功响应 res.status(201).json({ success: true, count: result.length }) } catch (err) { // 统一捕获错误处理 next(err) } }
补充说明
如果你的场景要求严格保证入库顺序,或者数据量极大需要避免数据库压力过高,可以把Promise.all改回串行for...of遍历:
for (const battle of battleList) { const post = new PostBattle(battle) await post.save() }
内容的提问来源于stack exchange,提问作者Sharan Balani
相关产品推荐
相关产品推荐

