MongoDB:如何进行文本搜索并按日期排序

标签 mongodb sorting

上下文:我有一个 MongoDB,里面填充了大量电子邮件。我想搜索包含以下任意字段中给定电子邮件地址的所有电子邮件:“收件人”、“发件人”、“抄送”和“密件抄送”。结果需要按日期字段排序。我们当前正在尝试以下查询:

db.collection.find({ $text : {$search: "\"email@domain.com\""}}).sort({Date:1})

我尝试过创建包含日期的复合索引,但它不起作用。

有了这个索引...

db.collection.createIndex({Date: 1, From:"text", To:"text", CC:"text", BCC:"text"})

它给出错误 17007,因为日期应该具有相等匹配,因为它是前缀。这不是一个选项,因为我们希望收到所有电子邮件,无论日期如何。

还有这个其他索引...

db.collection.createIndex({From:"text", To:"text", CC:"text", BCC:"text", Date:1})

然后它会给出错误 17144,因为它超出了排序的内部限制。

我们已阅读以下内容:

Stackoverflow ref

Stackoverflow ref

mongoDB doc on compound index

在这些引用文献和其他引用文献中,我认为这是不可能的,但我不认为我们正在尝试做的事情是非典型的或开箱即用的。

我们做错了什么吗?有没有办法使用复合索引或任何其他 MongoDB 功能来执行此查询?

谢谢!

最佳答案

无论其他复合索引键如何,都需要包含 $meta对于“textScore”以获得正确的排序:

db.collection.find(
    { "$text": { "$search": "\"email@domain.com\""}},
    { "score": { "$meta": "textScore" } }
).sort({
    "score": { "$meta": "textScore" }, "Date": 1
})

因此,您自然希望首先按“分数”排序,然后按“日期”排序,以便根据搜索的相关性对事物进行正确排名。

索引的顺序并不重要,但当然你只能有“一个”文本索引。因此,请确保在创建之前删除所有其他内容:

db.collection.createIndex({ 
   "From": "text",
   "To": "text",
   "CC":"text", 
   "BCC": "text", 
   "Date":1
})

查找当前的索引:

db.collection.getIndicies()

或者只是放弃一切并重新开始:

db.collection.dropIndexes()

对于您似乎正在搜索的数据,我认为每个字段的常规复合索引应该更适合您。查找“电子邮件”地址应该是“完全匹配”,如果您希望每个字段有多个项目,那么它们应该是字符串数组,如下所示:

{
    "TO": ["bill@example.com"],
    "FROM": ["ted@example.com"],
    "CC": ["marty@example.com","sarah@example.com"],
    "BCC": [],
    "Date": ISODate("2015-07-27T13:42:05.535Z")
}

然后您需要每个字段都有单独的索引,可能与“日期”复合,如下所示:

db.email.createIndex({ "TO": 1, "Date": 1 })
db.email.createIndex({ "FROM": 1, "Date": 1 })
db.email.createIndex({ "CC": 1, "Date": 1 })
db.email.createIndex({ "BCC": 1, "Date": 1 })

并使用 $or 进行查询条件:

db.email.find({
    "$or": [
        { "TO": "sarah@example.com" },
        { "FROM": "sarah@example.com" },
        { "CC": "sarah@example.com" },
        { "BCC": "sarah@example.com" }
    ],
    "Date": { "$lt": new Date() }
})

如果你看.explain(true) (详细)输出,您应该看到获胜计划是所有指定索引的“索引交集”。事实证明,这是非常有效的,因为每个字段(和选定的索引)都有一个精确匹配值,以及索引日期的范围匹配。

这对您来说比文本搜索的“模糊匹配”要好得多。一般来说,甚至正则表达式在这里也应该工作得更好(对于电子邮件地址),特别是如果它们“锚定”^ 到字符串的开头。

文本索引用于匹配“类似单词的标记”,但这不应该是您的数据。 $or 看起来不太好,但它应该做得更好。

关于MongoDB:如何进行文本搜索并按日期排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31652975/

相关文章:

algorithm - 使用堆排序对 0 和 1 数组进行排序的时间复杂度是多少?

php - 如何使用 CodeIgniter 进行表格排序?

php - 如何在数组中查找并计算相同的值,然后插入包含 : ‘count: (int)’ via PHP? 的节点

javascript - 如何在 join sails js 中添加另一个字段

mongodb - mongodb中如何将字符串转换为日期?

mongodb - Grails GORM具有与MongoDB不一致的许多关联,当尝试获取子记录时,有时会获取记录,有时却不获取

c++ - 对没有比较器或 lambda 函数的 vector 进行排序?

json - Mongoose 返回空对象,在 mongo shell 中工作

mongodb - meteor JS : How to get latest set of data based on the date?

javascript - 用另一个数组对一个对象数组进行排序