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

如何在Mongoose中实现MongoDB数组的部分字符串匹配?

解决方案

1. 实现正确的URL修剪函数

首先需要把输入的完整URL处理成不带协议、www前缀、查询参数、哈希值的主机名+路径格式,这是匹配的基础:

function trim(findUrl: string): string {
  try {
    const urlObj = new URL(findUrl);
    // 移除www前缀(如果存在)
    const hostname = urlObj.hostname.replace(/^www\./, '');
    // 拼接主机名和路径,移除末尾多余斜杠
    let trimmed = `${hostname}${urlObj.pathname}`.replace(/\/$/, '');
    return trimmed;
  } catch (error) {
    // 处理无效URL,直接返回空字符串避免错误查询
    return '';
  }
}

2. MongoDB查询逻辑

核心需求是:找到sites文档中,urls数组里存在至少一个条目是修剪后URL的前缀(即修剪后URL以该条目开头)。

使用MongoDB的$expr表达式结合$anyElementTrue、$map和$indexOfBytes来实现这个逻辑:

public async lookup(findUrl: string) {
  const trimmed = trim(findUrl);
  if (!trimmed) return [];

  // 查询符合条件的站点
  const matchedSites = await Site.find({
    $expr: {
      $anyElementTrue: {
        $map: {
          input: "$urls",
          as: "siteUrl",
          in: {
            // 检查修剪后的URL是否以当前siteUrl开头(索引位置为0)
            $eq: [0, { $indexOfBytes: [trimmed, "$$siteUrl"] }]
          }
        }
      }
    }
  }).select('name').lean(); // 只返回需要的name字段,提升性能

  // 提取站点名称返回,符合示例格式
  return matchedSites.map(site => site.name);
}

3. 各场景验证

  • 场景1:修剪后的URL为amazon.com/Coffee-Program-Ceramic-Makes-Programmers/dp/B07D2XJLLG,MySite的urls中amazon.com/Coffee是它的前缀,匹配成功,返回[MySite]。
  • 场景2:修剪后的URL为google.com/search,两个站点的urls都包含该条目,匹配成功,返回[MySite, OtherSite]。
  • 场景3:修剪后的URL为microsoft.com/en-us/surface,OtherSite的urls中microsoft.com/en-us是它的前缀,匹配成功,返回[OtherSite]。
  • 场景4:修剪后的URL为microsoft.com/nl-nl或microsoft.com,没有任何站点的urls条目是它们的前缀,返回[]。

性能优化建议

如果sites集合数据量较大,上述查询会触发全表扫描,可通过以下方式优化:

  1. 统一大小写:插入文档时将urls条目转为小写,修剪函数也返回小写字符串,避免大小写不匹配的同时,可提升后续索引效率。
  2. 拆分存储路径:将urls中的每个条目拆分为hostname和path两个字段单独存储,先通过hostname过滤缩小范围,再匹配路径前缀,减少需要处理的数据量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 14:30:40