如何基于用户输入用NodeJS查询带多WHERE条件的PSQL数据库
解决方案
1. 修改后端接口:支持多类型参数传递
将原路径参数改为查询参数,以便传递多个品类值(用逗号分隔)。修改后的Express接口如下:
app.get('/getInventoryItems', (request, response) => { const { types } = request.query; if (!types) { return response.status(400).json({error: '请指定要查询的品类'}); } // 将逗号分隔的字符串拆分为品类数组 const typeArray = types.split(','); const db = dbService.getDbServiceInstance(); const result = db.getInventoryItems(typeArray); result .then(data => response.json({data : data})) .catch(err => { console.log(err); response.status(500).json({error: '查询失败'}); }); })
2. 修改数据库查询方法:动态生成安全的条件语句
使用参数化查询避免SQL注入,用IN替代多个OR(效果一致且代码更简洁):
async getInventoryItems(typeArray) { try { const response = await new Promise((resolve, reject) => { // 为每个品类生成一个占位符,如['tortilla','side']对应'?,?' const placeholders = typeArray.map(() => '?').join(','); // 构造带IN条件的SQL语句 const query = `SELECT * FROM cabo_grill WHERE type IN (${placeholders}) AND id > 0 ORDER BY id ASC;`; connection.query(query, typeArray, (err, results) => { if (err) reject(new Error(err.message)); else resolve(results); }); }); return response; } catch (error) { console.log(error); throw error; // 抛出错误交由上层接口处理 } }
注:
type IN ('a','b')与type='a' OR type='b'功能完全等价,前者代码更简洁易维护。
3. 前端修改:处理多选按钮状态并发送请求
假设你的页面上有多个品类按钮(如#proteinBtn、#tortillaBtn),通过维护选中状态集合,实现点击切换并发送动态请求:
// 维护选中的品类集合(自动去重) const selectedTypes = new Set(); // 给所有品类按钮绑定点击事件 document.querySelectorAll('.category-btn').forEach(btn => { btn.addEventListener('click', () => { const type = btn.dataset.type; // 假设按钮带有data-type="protein"属性 // 切换选中状态 if (selectedTypes.has(type)) { selectedTypes.delete(type); btn.classList.remove('active'); } else { selectedTypes.add(type); btn.classList.add('active'); } // 发送查询请求 fetchSelectedInventory(); }); }); // 全选按钮逻辑 document.getElementById('allBtn').addEventListener('click', () => { const allTypes = ['protein', 'tortilla', 'side']; // 替换为实际所有品类 // 切换全选/清空状态 if (selectedTypes.size === allTypes.length) { selectedTypes.clear(); document.querySelectorAll('.category-btn').forEach(btn => btn.classList.remove('active')); } else { allTypes.forEach(type => selectedTypes.add(type)); document.querySelectorAll('.category-btn').forEach(btn => btn.classList.add('active')); } fetchSelectedInventory(); }); // 根据选中品类发送查询请求 function fetchSelectedInventory() { if (selectedTypes.size === 0) { // 未选中任何品类时,查询全部数据 fetchAllInventory(); return; } // 将集合转为逗号分隔的字符串 const typesStr = Array.from(selectedTypes).join(','); fetch(`https://project3-7bzcyqo3va-uc.a.run.app/getInventoryItems?types=${typesStr}`) .then(response => response.json()) .then(data => loadHTMLTable(data['data'])) .catch(err => console.log(err)); } // 保留原全量查询函数 function fetchAllInventory() { fetch('https://project3-7bzcyqo3va-uc.a.run.app/getAllInventory') .then(response => response.json()) .then(data => loadHTMLTable(data['data'])) .catch(err => console.log(err)); }
关键注意事项
- 防SQL注入:必须使用参数化查询,绝对不能直接将用户输入拼接进SQL语句,上述代码通过占位符+参数数组的方式彻底避免了注入风险。
- 接口兼容:若需要兼容原有单品类查询,可以保留
/getInventoryItem/:type接口,新增/getInventoryItems接口处理多品类场景。 - 状态管理:使用
Set维护选中品类可自动去重,避免重复添加同一品类导致的冗余查询。
内容的提问来源于stack exchange,提问作者BrandonMoon01
相关产品推荐
相关产品推荐

