mongodb数组中使用mongose的部分字符串匹配



我有一个MongoDB集合,它看起来像这样:

// sites
// note that these urls all have paths, this is important.
// The path can only be longer, e.g. amazon.com/Coffee-Mug
[
{
name: "MySite",
urls: ['google.com/search', 'amazon.com/Coffee', 'amazon.com/Mug']
},
{
name: "OtherSite",
urls: ['google.com/search', 'microsoft.com/en-us']
}
]

我想做的是:

class Service {
/**
* @param url Is a full url, like "https://www.google.com/search?q=stackoverflow"
* or "https://www.amazon.com/Coffee-Program-Ceramic-Makes-Programmers/dp/B07D2XJLLG/"
*/
public async lookup(findUrl: string) {
const trimmed = trim(findUrl); // remove variables and https, but NOT the path!
// return the "Site" in which the base url is matched with the full url
// see description below
}
}

例如,使用这些情况

情况1:

  • url = 'https://www.amazon.com/Coffee-Program-Ceramic-Makes-Programmers/dp/B07D2XJLLG/'
  • 返回的站点:[MySite]

情况2:

  • url = 'https://www.google.com/search?q=stackoverflow'
  • 返回的站点:[MySite, OtherSite]

情况3(与情况1相同,但有其他值(:

  • url = 'https://www.microsoft.com/en-us/surface'
  • 返回的站点:[OtherSite]

情况4(不匹配时(:

  • url = 'https://microsoft.com/nl-nl'
  • url = 'https://microsoft.com'
  • 返回的站点:[]

我试过这样做:

Site.find({ url: { $in: trimmed }})

上面这类工作,但问题是,这只做精确匹配。我想将MongoDB中的url与函数提供的url进行匹配。如何做到这一点?

我收到了在MongoDB上使用检查字段是否是字符串的子字符串或文本搜索的建议,但这太不准确了。我基本上可以在没有路径的情况下进入基本域,它会找到它,这绝对不应该发生。

一个选项是使用$reduce$filter对站点和URL进行迭代,并将它们与regexMatch匹配。然后,由于请求的输出是url数组,而不是对象数组,因此我们可以使用$facet来处理根本没有匹配的情况。

db.collection.aggregate([
{$match: {$expr: {
$gt: [{
$size: {
$reduce: {
input: urls_array,
initialValue: [],
in: {$concatArrays: [
"$$value",
{$filter: {
input: "$urls",
as: "url",
cond: {$regexMatch: {input: "$$this", regex: "$$url"}}
}}
]}
}
}
}, 0]
}}},
{$facet: {res: [{$group: {_id: 0, res: {$addToSet: "$name"}}}]}},
{$replaceRoot: {newRoot: {$mergeObjects: [{res: []}, {$first: "$res"}]}}}
])

看看它是如何在操场上工作的例子

我想不出任何直接的方法,你可以使用聚合运算符,但它会执行得很慢,因为它不会使用索引,如果你真的想的话,我在下面添加了一种方法,

  • $expr允许在查询部分使用聚合运算符
  • $map迭代urls数组的循环,这将返回一个布尔值
  • $replaceAll将URL字符串中的/替换为.
  • $regexMatch将输入字符串与上面生成的字符串匹配,该字符串将作为正则表达式字符串输入,如果字符串模式匹配,则返回true,否则返回false
  • $in检查上述值是否为真
Site.find({
$expr: {
$in: [
true,
{
$map: {
input: "$urls",
in: {
$regexMatch: {
input: trimmed, // your input variable
regex: {
$replaceAll: {
input: "$$this",
find: "/",
replacement: "."
}
},
options: "i"
}
}
}
}
]
}
})

游乐场

最新更新