MongoDB查询问题:如何匹配lowongan数组中指定字段的对象
问题:MongoDB数组匹配查询返回结果异常,无法获取符合条件的lowongan对象
尝试从lowongan数组中查找匹配指定country和job_title的对象,但当前查询仅返回随机的_id,无法得到预期结果。
数据Schema
employer schema = { name : String, lowongan : [object] }
原查询代码
import Employer from "@/model/employer"; import { connectToDB } from "@/utils/conectDb"; export default async function find(req, res) { if (req.method === "POST") { try { await connectToDB(); const { job_title, country } = req.body; const { page } = req.query; const itemsPerPage = 10; const currentPage = parseInt(page) || 1; const limit = itemsPerPage * currentPage; const cari = await Employer.find( {}, { lowongan: { $elemMatch: { job_title: job_title, country: country, }, }, }, // Optional: Use projection to include only the matching "lowongan" objects { "lowongan.$": 1 } ).limit(limit); if (!cari || cari.length === 0) { res.status(404).json({ message: "No matching employers found." }); return; } res.status(200).json(cari); } catch (error) { console.error(error.message); res.status(500).json({ err: "Internal server error" }); } } }
尝试过的无效查询
employer.find({},{ lowongan : 1 , job_title : job_title })
问题原因分析
- 原查询第一个参数为空对象
{},会匹配所有Employer文档,未筛选包含符合条件lowongan的目标文档。 - 同时使用
$elemMatch投影和lowongan.$投影,逻辑冲突导致无法正确返回匹配元素。 - 分页计算错误:
limit = itemsPerPage * currentPage会导致每页返回数量递增,不符合常规分页逻辑。
修正后的查询方案
方案1:返回每个雇主的第一个匹配lowongan元素
如果只需获取每个Employer文档中第一个符合条件的lowongan对象,可使用以下代码:
import Employer from "@/model/employer"; import { connectToDB } from "@/utils/conectDb"; export default async function find(req, res) { if (req.method === "POST") { try { await connectToDB(); const { job_title, country } = req.body; const { page } = req.query; const itemsPerPage = 10; const currentPage = parseInt(page) || 1; const skip = (currentPage - 1) * itemsPerPage; const cari = await Employer.find( // 先筛选包含目标lowongan的雇主文档 { lowongan: { $elemMatch: { job_title: job_title, country: country, }, }, }, // 投影出匹配的lowongan元素和需要的字段 { name: 1, lowongan: { $elemMatch: { job_title: job_title, country: country, }, }, _id: 0 // 可选,隐藏默认返回的_id字段 } ) .skip(skip) .limit(itemsPerPage); if (!cari || cari.length === 0) { res.status(404).json({ message: "No matching employers found." }); return; } res.status(200).json(cari); } catch (error) { console.error(error.message); res.status(500).json({ err: "Internal server error" }); } } }
方案2:返回每个雇主的所有匹配lowongan元素(推荐)
如果需要获取Employer文档中所有符合条件的lowongan对象,使用聚合管道更合适:
import Employer from "@/model/employer"; import { connectToDB } from "@/utils/conectDb"; export default async function find(req, res) { if (req.method === "POST") { try { await connectToDB(); const { job_title, country } = req.body; const { page } = req.query; const itemsPerPage = 10; const currentPage = parseInt(page) || 1; const skip = (currentPage - 1) * itemsPerPage; const cari = await Employer.aggregate([ // 筛选包含目标lowongan的雇主文档 { $match: { lowongan: { $elemMatch: { job_title: job_title, country: country, }, }, }, }, // 过滤lowongan数组,只保留符合条件的元素 { $addFields: { lowongan: { $filter: { input: "$lowongan", as: "item", cond: { $and: [ { $eq: ["$$item.job_title", job_title] }, { $eq: ["$$item.country", country] }, ], }, }, }, }, }, // 分页处理 { $skip: skip }, { $limit: itemsPerPage }, // 可选:自定义返回字段 { $project: { _id: 0, name: 1, lowongan: 1 } } ]); if (!cari || cari.length === 0) { res.status(404).json({ message: "No matching employers found." }); return; } res.status(200).json(cari); } catch (error) { console.error(error.message); res.status(500).json({ err: "Internal server error" }); } } }
关键修正点
- 新增
$match阶段筛选目标文档,避免返回无关数据。 - 使用
$filter聚合操作符可提取数组中所有符合条件的元素($elemMatch投影仅返回第一个匹配项)。 - 分页逻辑改为
skip((currentPage-1)*itemsPerPage).limit(itemsPerPage),实现标准分页效果。 - 移除冲突的投影参数,确保查询逻辑一致。
内容的提问来源于stack exchange,提问作者adityamms
相关产品推荐
相关产品推荐

