首页 > 解决方案 > 检查字段是否是 MongoDB 上的字符串或文本搜索的子字符串

问题描述

需要检查该字段是否是给定输入字符串的子字符串,不敏感模式。

样本文件:

{
    "_id" : ObjectId("5e6ffe413f71835ae3aa4b60"),
    "f" : "Paul",
    "id" : 11811,
    "l" : "Green",
    "r" : 64
  }

如果字符串是Paul Green我想得到这个项目所以我尝试做这个查询:

db.getCollection('players').find({$or: [{'f': {'$regex': 'Paul Green', '$options': 'i'}},{'l': {'$regex': 'Paul Green', '$options': 'i'}}]})

没有结果。我也希望像pele这样的搜索会给我pelè

我怎样才能做到这一点?

标签: mongodbmongodb-queryaggregation-framework

解决方案


更新答案:

据我了解,您想实现搜索功能,那么您可以查看专门为文本搜索实现的 MongoDB 中的文本索引,根据我实现模糊/部分/全文/变音符号/不区分大小写文本等文本搜索的经验搜索非常有帮助。

所以我的建议是,因为您正在搜索两个字段f-l我建议将两个字段合并到一个字段中fl并在其上创建一个文本索引,这样您的查询将针对一个对搜索更有效的字段,请查看以下建议:

第 1 步:如果您尚未创建合并字段,您现在可以通过 MongoDB v 上的此查询来执行此操作>=4.2(在较低版本中,您需要找到一种方法来执行Read Coll & update fielduse aggregation + $out):

db.collection.update({},[{$addFields : {'fl': { $concat: [ "$f", " ", "$l" ] }}}],{multi:true})

第 2 步:fl在字段上创建文本索引:

db.collection.createIndex( { fl: "text" } )

第 3 步:您可以进行如下搜索,作为响应{fl :0}删除字段的可选投影。fl

db.collection.find( { $text: { $search: "Paul Green" } }, {fl :0} )

注意:现在您可以获得所有文档,其中有PaulfGreen 或 PAUL 或 GREEN 或 PAUL GREEN 或 Greèn 或 PAU 或 Pau 或 Gre 或 GRE,所以大部分都得到了整理。如果您不研究文本搜索,您仍然会研究以下方法。l


实际答案:

通常,当您想检查字符串字段中存在的输入值时 - 您会使用正则表达式来获取过滤后的文档。

但是,当您想传入一个字符串'Paul Green'并检查一个字段是 pass'd 输入的子字符串时,普通的正则表达式对您没有帮助。但是,如果您使用的是 MongoDB 版本4.2,您可以执行以下操作:

查询 1:

db.collection.aggregate([
  /** Add a field which will be true if any of the field 'f' or 'l' is a sub-string of input (Case-insensitive) */
  {
    $addFields: {
      result: {
        $or: [
          { $regexMatch: { input: "Paul Green", regex: "$f", options: "i" } }, /** Usually input is field & regex is actual input value, we tricked it for our requirement */
          { $regexMatch: { input: "Paul Green", regex: "$l", options: "i" } }
        ]
      }
    }
  },
  /** Filter for all docs where result field is true (Which leave docs where 'f' or 'l' is sub-string) */
  { $match: { result: true } },
  /** Remove added field result */
  { $project: { result: 0 } }
]);

测试: MongoDB-游乐场

注意:即使像发送输入字符串一样,上面的查询也可以工作,'PaulGreen'但缺点是它不会像你想要的那样给你结果:像 pele 这样的搜索会给我 pelè,因为如果你想得到那种数据,那么您需要使用如果我们使用$regexMatch则无法使用的排序规则。因此,根据您的数据,您可以执行以下操作:

查询 2:

根据空格['Paul', 'Green']拆分字符串并传入查询:

db.collection.aggregate(
  /** Filter docs if any of the word exists in any of the fields 'f' or 'l' */
  [
    {
      $match: {
        $or: [
          { f: { $in: ["Paul", "Green"] } },
          { l: { $in: ["Paul", "Green"] } }
        ]
      }
    }
  ],
  { collation: { locale: "fr", strength: 1 } } // Applied collation ignores case & diacritics
);

注意:以上查询可能主要使用 MongoDB 版本完成您的工作 > 3.4,但如果您想搜索类似'PaulGreen'的内容,则无法正常工作,由于某种原因,此查询的排序规则在 mongodb 操场上不起作用 - 请在实际数据库上进行测试。


推荐阅读