Next.js中MongoDB关联文档find查询失效,求可行解决方案
问题描述
我从localhost:3000/api/notes/[noteTitle]/note2获取的数据结构如下:
{ "data": [ { "_id": "62ff418fa4adfb3a957a2847", "title": "first-note2", "note": { "_id": "62ff399da4adfb3a957a2808", "title": "first" }, }, { "_id": "631af43b054a6aef1a7c4f08", "title": "first-note22", "note": { "_id": "62ff399da4adfb3a957a2808", "title": "first" }, }, { "_id": "631af504054a6aef1a7c4f11", "title": "second-note22", "note": { "_id": "62ff3a10a4adfb3a957a2817", "title": "second" }, } ] }
当向localhost:3000/api/notes/first/note2发送GET请求时,希望仅返回note对象中title为"first"的数据。
尝试了以下API代码,但返回空数组(实际应有2条匹配数据):
export default async (req, res) => { const { query: { noteTitle }, method } = req; switch (method) { case "GET": try { const notes = await Note2.find({"note.title": noteTitle}).populate("note"); res.status(200).json({ success: true, data: notes }); } catch (error) { console.log(error); } break; default: res.status(400).json({ success: false }); break; } };
相关Schema定义:
- Note2 Schema:
const Note2Schema = new mongoose.Schema({ title: { type: String, unique: true }, note: { type: mongoose.Schema.Types.ObjectId, ref: "Note" }, }); module.exports = mongoose.models.Note2 || mongoose.model("Note2", Note2Schema);
- Note Schema:
const NoteSchema = new mongoose.Schema({ title: { type: String, unique: true } }); module.exports = mongoose.models.Note || mongoose.model("Note", NoteSchema);
查阅Mongoose文档得知:无法在find中使用populate后的关联字段筛选主文档,示例如下:
通常,无法通过populate()根据关联文档(如故事的作者)的属性来筛选主文档。例如,以下查询不会返回任何结果,即使author已被populate。
const story = await Story. findOne({ 'author.name': 'Ian Fleming' }). populate('author'). exec(); story; // null
需要实现按关联文档note的title筛选Note2数据的变通方案。
解决方案
方法1:先查关联文档ID,再筛选主文档
先通过Note模型找到对应title的文档ID,再用该ID查询Note2:
export default async (req, res) => { const { query: { noteTitle }, method } = req; switch (method) { case "GET": try { // 第一步:获取目标Note的ID const targetNote = await Note.findOne({ title: noteTitle }); if (!targetNote) { return res.status(200).json({ success: true, data: [] }); } // 第二步:用Note的ID筛选Note2并关联查询 const notes = await Note2.find({ note: targetNote._id }).populate("note"); res.status(200).json({ success: true, data: notes }); } catch (error) { console.log(error); res.status(500).json({ success: false, error: error.message }); } break; default: res.status(400).json({ success: false }); break; } };
方法2:使用聚合管道关联筛选
通过$lookup关联集合,再用$match筛选符合条件的文档:
export default async (req, res) => { const { query: { noteTitle }, method } = req; switch (method) { case "GET": try { const notes = await Note2.aggregate([ // 关联Note集合,匹配结果存入note字段 { $lookup: { from: "notes", // Note模型对应的集合名(默认是小写复数) localField: "note", foreignField: "_id", as: "note" } }, // 将note数组转为单个对象(一对一关联场景) { $unwind: "$note" }, // 筛选note.title匹配的文档 { $match: { "note.title": noteTitle } } ]); res.status(200).json({ success: true, data: notes }); } catch (error) { console.log(error); res.status(500).json({ success: false, error: error.message }); } break; default: res.status(400).json({ success: false }); break; } };
注意:from字段需填写Note模型对应的MongoDB集合名称,默认是模型名的小写复数形式(这里为notes),若你的集合名不同需自行修改。
方法3:populate带匹配条件(需手动过滤主文档)
若只是想过滤返回的关联数据,可使用这种方式,但需手动剔除关联数据为空的主文档,仅作参考:
export default async (req, res) => { const { query: { noteTitle }, method } = req; switch (method) { case "GET": try { const notes = await Note2.find().populate({ path: "note", match: { title: noteTitle }, select: "_id title" }); // 手动过滤掉note为null的文档 const filteredNotes = notes.filter(item => item.note !== null); res.status(200).json({ success: true, data: filteredNotes }); } catch (error) { console.log(error); res.status(500).json({ success: false, error: error.message }); } break; default: res.status(400).json({ success: false }); break; } };
内容的提问来源于stack exchange,提问作者Nasem
相关产品推荐
相关产品推荐

