Mongo $ text查询:返回文档"以字符串开头"之前的其他字符串

Pat*_*der 14 indexing mongodb fulltext-index

比方说,我有一个蒙戈集合与text indexitemName这些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
}
Run Code Online (Sandbox Code Playgroud)

然后我执行一个这样的查询:

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

返回字符串中某处包含"Car"的任何其他文档之前,如何强制mongo 返回以"Car"开头的文档(不区分大小写)?itemName

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

[
    {..., itemName: 'Carrot Juice', ...},
    {..., itemName: 'Mashed carrots with big carrot pieces', ...}
]
Run Code Online (Sandbox Code Playgroud)

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

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

编辑:

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

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

在查询时,它就像一个魅力并返回所有这些文档

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

不归还任何东西!只有将"Zwiebel"改为"Zwie"才能获得$search.

我真的不明白这是怎么回事?!

最好的,P

fel*_*lix 9

解决方案是使用MongoDB 3.4中$indexOfCP操作符

此运算符返回另一个String中String的出现的索引,如果没有出现则返回-1

这个怎么运作:

  1. 使用正则表达式过滤掉所有不包含'car'的文档:(不/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
      }
   }
])
Run Code Online (Sandbox Code Playgroud)

这会返回:

{ "_id" : 2, "itemName" : "Carrot juice", "price" : 0.79, "index" : 0 }
{ "_id" : 1, "itemName" : "Mashed carrots with big carrot pieces", "price" : 1.29, "index" : 7 }
Run Code Online (Sandbox Code Playgroud)

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

编辑:

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

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

来自mongodb文本索引文档

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