带有部分字符串的猫鼬文本搜索

Posted

技术标签:

【中文标题】带有部分字符串的猫鼬文本搜索【英文标题】:Mongoose text-search with partial string 【发布时间】:2016-05-11 04:33:09 【问题描述】:

您好,我正在使用 mongoose 来搜索我收藏中的人。

/*Person model*/

    name: 
       first: String,
       last: String
    

现在我想搜索有查询的人:

let regex = new RegExp(QUERY,'i');

Person.find(
   $or: [
      'name.first': regex,
      'name.last': regex
   ]
).exec(function(err,persons)
  console.log(persons);
);

如果我搜索 John,我会得到结果(如果我搜索 Jo,则会发生事件)。 但是,如果我搜索 John Doe,我显然没有得到任何结果。

如果我将 QUERY 更改为 John|Doe 我会得到结果,但它会返回所有拥有 JohnDoe 的人 在他们的姓/名中。

接下来是尝试使用 mongoose 文本搜索:

首先将字段添加到索引:

PersonSchema.index(
   name: 
      first: 'text',
      last: 'text'
   
,
   name: 'Personsearch index',
   weights: 
      name: 
          first : 10,
          last: 10
   

);

然后修改Person查询:

Person.find( 
    $text :  
        $search : QUERY
     
,
 score:$meta:'textScore' )
.sort( score :  $meta : 'textScore'  )
.exec(function(err,persons)
    console.log(persons);
);

这很好用! 但是现在只返回与整个名字/姓氏匹配的人:

-> John 返回值

-> Jo 不返回任何值

有没有办法解决这个问题?

没有外部插件的答案是首选,但也希望其他答案。

【问题讨论】:

您可能需要为此使用 Elasticsearch。如果您愿意,我可以为您提供详细的代码。为了获得全名搜索,您应该以 \"query"\ 格式输入查询。 只用猫鼬进行部分搜索是行不通的。在选择弹性之前,我尝试了 3 天。 感谢您的提示,但对于这种情况,Elastiq 似乎有点过分了。如果有可能将名字和姓氏合并到一个字段中(仅用于一个查询),然后使用正则表达式进行搜索就可以了。但是我不确定猫鼬是否可以做到这一点? 所以您需要自动完成(通配符查询,如“phrase*”)名字和姓氏,但想分别存储? 请看:virtuals 可以合并两个字段。 【参考方案1】:

您可以使用aggregate 管道来执行此操作,该管道使用$concat 将名字和姓氏连接在一起,然后对其进行搜索:

let regex = new RegExp(QUERY,'i');

Person.aggregate([
    // Project the concatenated full name along with the original doc
    $project: fullname: $concat: ['$name.first', ' ', '$name.last'], doc: '$$ROOT',
    $match: fullname: regex
], function(err, persons) 
    // Extract the original doc from each item
    persons = persons.map(function(item)  return item.doc; );
    console.log(persons);
);

然而,性能是一个问题,因为它不能使用索引,因此需要完整的集合扫描。

您可以通过在 $project 阶段之前使用 $match 查询来缓解这种情况,可以使用索引来减少管道其余部分需要查看的文档集。 p>

因此,如果您分别索引name.firstname.last,然后将搜索字符串的第一个单词作为锚定查询(例如/^John/i),您可以在管道开头添加以下内容:

$match: $or: [
  'name.first': /^John/i,
  'name.last': /^John/i
]

显然,您需要以编程方式生成“第一个单词”正则表达式,但希望它能给您带来想法。

【讨论】:

这种正则表达式方法在大规模上表现是否足够好?【参考方案2】:

正则表达式可以帮助您。

Person.find( "name":  "$regex": "Alex", "$options": "i"  ,
function(err,docs)  
);

【讨论】:

你在哪里找到这个文档? 我浏览了一些帖子。我不完全记得它们,但它经过试验和测试。您可以在代码中使用它。 有效,但除了这里,我在任何地方都找不到这个文档。谢谢!! @TJBlackman 虽然这是关于 Mongoose 的问题,但 $regex 运算符是 Mongoose 用来查询集合的 Mongo 运算符。 docs.mongodb.com/manual/reference/operator/query/regex【参考方案3】:

一)。 在集合中的单个字段中进行部分文本搜索:

如果我们想在集合中的单个字段中搜索,我们可以使用聚合代码


  $match: 
    name: 
      $regex: “String seraching”,
      ‘$options’: ‘i’
      
   

b)。 通过集合中的多个字段进行部分文本搜索:

如果我们想在特定集合中搜索多个字段(多个字段),那么我们可以在聚合查询中使用该代码


  $match: 
    $or: [
      name: 
       $regex: “String to be searched”,
       ‘$options’: ‘i’
     ,
      email: 
       $regex: String to be searched,
       ‘$options’: ‘i’
     
    ]

,

【讨论】:

以上是关于带有部分字符串的猫鼬文本搜索的主要内容,如果未能解决你的问题,请参考以下文章

带有可选参数的猫鼬复杂查询?

UserModel 不可分配给 Document | 类型的参数nulll [带有 Typescript 的猫鼬]

具有多个和可选字段的猫鼬查找

用于多个对象数组的猫鼬嵌套模式

带有打字稿的猫鼬,来自猫鼬的错误“连接”

寻找访问字符串的猫鼬数组