Node.js/Express+Mongoose接口findOne返回全部数据的修复
问题:如何通过Node.js/Express + Mongoose返回指定ID的单条事件数据
预期返回格式
请求localhost:3000/api/one/3000时,预期仅返回指定ID的单条事件:
{ "id": 3000, "group": 3, "title": "", "start_time": "2023-07-31T11:00:00.000Z", "end_time": "2023-07-31T20:00:00.000Z", "category": "green" }
实际返回格式
实际接口返回了用户名下的所有事件数据:
{ "_id": "658", "schedule": [ { "events": [ { "id": 3000, "group": 3, "title": "", "start_time": "2023-12-01T11:00:00.000Z", "end_time": "2023-12-01T20:00:00.000Z", "category": "green" }, { "id": 3001, "group": 3, "title": "", "start_time": "2023-12-02T11:00:00.000Z", "end_time": "2023-12-02T20:00:00.000Z", "category": "green" }, { "id": 3002, "group": 3, "title": "", "start_time": "2023-12-03T11:00:00.000Z", "end_time": "2023-12-03T20:00:00.000Z", "category": "green" }, { "id": 3003, "group": 3, "title": "", "start_time": "2023-12-04T11:00:00.000Z", "end_time": "2023-12-04T20:00:00.000Z", "category": "green" }, { "id": 3004, "group": 3, "title": "", "start_time": "2023-12-07T11:00:00.000Z", "end_time": "2023-12-07T20:00:00.000Z", "category": "green" } ] } ] }
MongoDB Schema定义
import mongoose, { model, Schema } from "mongoose"; const eventSchema = new mongoose.Schema({ id: Number, group: Number, title: String, start_time: Date, end_time: Date, category: String, }); const individualSchema = new mongoose.Schema({ name: String, events: [eventSchema], }); const ScheduleSchema = new mongoose.Schema({ schedule: [individualSchema], }); export default model("Schedule", ScheduleSchema);
当前查询函数
export const getById = async (req, res) => { try { const id = req.params.id; const found = await ScheduleSchema.findOne( { "schedule.events.id": id }, { "schedule.events.$": 1 } ); res.json(found); } catch (error) { console.log(error); console.error(error); } };
解决方案
问题根源
当前findOne结合位置运算符$仅能匹配第一层嵌套数组(schedule)的第一个匹配项,无法深入第二层数组(events)提取单个事件,因此返回的仍是包含所有事件的嵌套结构。另外,req.params.id是字符串类型,与Schema中id的Number类型不匹配,会导致精准匹配失效。
方案1:使用聚合管道(推荐,数据库层面完成过滤)
通过MongoDB聚合管道逐层解开嵌套数组,匹配目标事件后直接返回单条数据:
export const getById = async (req, res) => { try { const eventId = parseInt(req.params.id); // 转换为数字类型匹配Schema定义 const result = await ScheduleSchema.aggregate([ // 解开schedule数组,将每个元素拆分为独立文档 { $unwind: "$schedule" }, // 解开events数组,将每个事件拆分为独立文档 { $unwind: "$schedule.events" }, // 匹配指定ID的事件 { $match: { "schedule.events.id": eventId } }, // 将事件数据作为根文档返回,去除外层嵌套 { $replaceRoot: { newRoot: "$schedule.events" } } ]); if (result.length > 0) { res.json(result[0]); } else { res.status(404).json({ message: "Event not found" }); } } catch (error) { console.error(error); res.status(500).json({ message: "Server error" }); } };
方案2:查询后手动提取事件(代码层面处理)
若不想使用聚合,可在查询到完整数据后,通过遍历嵌套数组筛选目标事件:
export const getById = async (req, res) => { try { const eventId = parseInt(req.params.id); const found = await ScheduleSchema.findOne( { "schedule.events.id": eventId } ); if (!found) { return res.status(404).json({ message: "Event not found" }); } // 遍历嵌套结构找到目标事件 let targetEvent = null; for (const individual of found.schedule) { targetEvent = individual.events.find(event => event.id === eventId); if (targetEvent) break; } targetEvent ? res.json(targetEvent) : res.status(404).json({ message: "Event not found" }); } catch (error) { console.error(error); res.status(500).json({ message: "Server error" }); } };
内容的提问来源于stack exchange,提问作者Felipe Useda
相关产品推荐
相关产品推荐

