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

MongoDB单查询跨多集合多字段搜索问题(用aggregate与populate)

问题描述

我们拥有Ad和Company两个MongoDB集合,一个公司可关联多个广告。需要开发API接口,支持通过关键词在公司名称、primaryText、headline、description字段中搜索匹配的广告,要求使用aggregate与populate函数。

提供的Mongoose Schema如下:

Company Schema

const CompanySchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
  },
  url: {
    type: String,
    required: true,
  },
});

const Company = mongoose.model("company", CompanySchema);

Ad Schema

const AdSchema = new mongoose.Schema({
  primaryText: {
    type: String,
    required: true,
  },
  companyId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "company",
    required: true,
  },
  headline: {
    type: String,
    required: true,
  },
  description: {
    type: String,
    required: false,
    default: "",
  },
  CTA: {
    type: String,
    required: true,
  },
  imageUrl: {
    type: String,
    required: true,
  },
});

AdSchema.index({ primaryText: 'text', headline: 'text', description: 'text' });
const Ad = mongoose.model("ad", AdSchema);

现有实现代码无法通过公司名称搜索,代码如下:

router.get("/search", async function (req, res, next) {
  const query = req.query.query;

  const ads = await Ad.aggregate([
    {
      $match: {
        $text: {
          $search: query,
        },
      },
    },
    {
      $lookup: {
        from: "companies",
        localField: "companyId",
        foreignField: "_id",
        as: "company",
      },
    },
    {
      $unwind: "$company",
    },
  ]);
  res.json(ads);
});

现有代码的问题

  • 文本索引覆盖不全:仅在Ad集合的primaryText、headline、description字段创建了文本索引,未包含关联Company集合的name字段,导致$text搜索无法匹配公司名称。
  • 搜索时机错误:$match阶段先过滤Ad自身字段,此时尚未关联Company数据,无法基于公司名称筛选结果。

正确实现方式

方案一:纯聚合流程实现

先关联Company数据,再同时匹配Ad自身字段和公司名称,若要对公司名称使用文本搜索,需先给Company集合添加文本索引:

// 先为Company集合添加文本索引
CompanySchema.index({ name: 'text' });

router.get("/search", async function (req, res, next) {
  const query = req.query.query;

  // 先搜索匹配关键词的公司ID
  const matchedCompanies = await Company.find(
    { $text: { $search: query } },
    { _id: 1 }
  );
  const companyIds = matchedCompanies.map(c => c._id);

  // 聚合筛选Ad自身字段匹配,或关联公司ID匹配的广告,再关联公司数据
  const ads = await Ad.aggregate([
    {
      $match: {
        $or: [
          { $text: { $search: query } },
          { companyId: { $in: companyIds } }
        ]
      }
    },
    {
      $lookup: {
        from: "companies",
        localField: "companyId",
        foreignField: "_id",
        as: "company",
      }
    },
    { $unwind: "$company" }
  ]);
  res.json(ads);
});

方案二:结合aggregate与populate实现

先用aggregate筛选符合条件的Ad,再通过populate关联Company数据,满足题目要求的两个函数使用:

// 先为Company集合添加文本索引
CompanySchema.index({ name: 'text' });

router.get("/search", async function (req, res, next) {
  const query = req.query.query;

  // 搜索匹配关键词的公司ID
  const matchedCompanies = await Company.find(
    { $text: { $search: query } },
    { _id: 1 }
  );
  const companyIds = matchedCompanies.map(c => c._id);

  // 聚合筛选Ad,再用populate关联公司数据
  const ads = await Ad.aggregate([
    {
      $match: {
        $or: [
          { $text: { $search: query } },
          { companyId: { $in: companyIds } }
        ]
      }
    }
  ]).populate({ path: 'companyId', model: Company });

  // 格式化字段名(可选,将companyId替换为company)
  const formattedAds = ads.map(ad => {
    const { companyId, ...rest } = ad;
    return { ...rest, company: companyId };
  });

  res.json(formattedAds);
});

内容的提问来源于stack exchange,提问作者Qazi Amaan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 18:10:32