You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
})

问题原因分析

  1. 原查询第一个参数为空对象{},会匹配所有Employer文档,未筛选包含符合条件lowongan的目标文档。
  2. 同时使用$elemMatch投影和lowongan.$投影,逻辑冲突导致无法正确返回匹配元素。
  3. 分页计算错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 08:01:23