14

假设我有一个 mongo 集合,其中text index包含itemName以下 3 个文档:

{
    _id: ...,
    itemName: 'Mashed carrots with big carrot pieces',
    price: 1.29
},
{
    _id: ...,
    itemName: 'Carrot juice',
    price: 0.79
},
{
    _id: ...,
    itemName: 'Apple juice',
    price: 1.49
}

然后我执行如下查询:

db.items.find({ $text: { $search: 'Car' } }, { score: { $meta: "textScore" } }).sort( { score: { $meta: "textScore" } } );

我如何强制 mongo返回以“Car”开头的文档不区分大小写)itemName在返回字符串中某处也包含“Car”的任何其他文档

所以我想按以下顺序检索文档:

[
    {..., itemName: 'Carrot Juice', ...},
    {..., itemName: 'Mashed carrots with big carrot pieces', ...}
]

当然,这意味着在搜索功能中使用,因此向用户显示项目是完全有意义的在显示之后的任何其他项目之前向用户显示以他的搜索字符串开头的项目是完全有意义的。

直到现在我都在使用标准的正则表达式,但这里的性能当然要差得多!+ 因为我必须搜索不区分大小写,根据文档,正常的正则表达式根本不使用任何索引?!

编辑:

此外,有时 的行为$text非常奇怪。例如,我有大约 10-15 项itemName以“Zwiebel”开头的项目。这个查询

db.items.find({ $text: { $search: "Zwiebel" }, supplier_id: 'iNTJHEf5YgBPicTrJ' }, { score: { $meta: "textScore" } }).sort( { score: { $meta: "textScore" } } );

像魅力一样工作并返回所有这些文档,而这个查询

db.items.find({ $text: { $search: "Zwie" }, supplier_id: 'iNTJHEf5YgBPicTrJ' }, { score: { $meta: "textScore" } }).sort( { score: { $meta: "textScore" } } );

不返回任何东西!只需将$search.

我真的不明白这怎么可能?!

最好的,P

4

1 回答 1

9

一种解决方案是使用MongoDB 3.4$indexOfCP中引入的运算符

该运算符返回一个字符串在另一个字符串中出现的索引,如果没有出现则返回-1

这个怎么运作:

  1. 使用正则表达式过滤掉所有不包含“汽车”的文档:(不/car/gi区分大小写)
  2. 创建一个名为的字段,该字段index将“car”的索引存储在itemName
  3. index对字段中的文档进行排序

查询看起来像这样:

db.items.aggregate([
   {
      $match:{
         itemName:/car/gi
      }
   },
   {
      $project:{
         index:{
            $indexOfCP:[
               {
                  $toLower:"$itemName"
               },
               "car"
            ]
         },
         price:1,
         itemName:1
      }
   },
   {
      $sort:{
         index:1
      }
   }
])

这会返回:

{ "_id" : 2, "itemName" : "Carrot juice", "price" : 0.79, "index" : 0 }
{ "_id" : 1, "itemName" : "Mashed carrots with big carrot pieces", "price" : 1.29, "index" : 7 }

在线尝试:mongoplayground.net/p/FqqCUQI3D-E

编辑:

对于$text索引的行为,这是完全正常的

文本索引使用分隔符对文本进行标记(默认分隔符是空格和标点符号)。它只能用于搜索整个世界,因此它不适用于单词的子部分

来自mongodb 文本索引文档

$text 将使用空格和大多数标点符号作为分隔符对搜索字符串进行标记,并对搜索字符串中的所有此类标记执行逻辑 OR。

于 2017-03-02T06:28:11.607 回答