我的 mailCollection 集合包含。发件人和。收件人值的索引。当我执行$或查询并按。 timestamp 排序时,将扫描整个集合。如何索引此集合或重写查询以获取文档。 sender 或。收件人匹配特定值,排序和限制?
mailCollection 索引:
{recipient: 1}
{sender: 1}
慢代码:
email = <some email address I want to query>;
cursor = mailCollection.find({$or: [{sender: email}, {recipient: email}]});
cursor.sort({timestamp: 1}).limit(100).toArray(function(error, result) {
//yikes, full collection scan
});
如果它有所作为,我使用MongoDb node.js驱动程序。
答案 0 :(得分:1)
狡猾。三向索引交叉点不起作用。所以你需要与复合索引相交。但是,您需要确保在复合索引中有正确的前缀,以便正确使用它并使其有效。
> db.indextest.find()
{ "_id" : ObjectId("59f401893e9fcadcbf2b1694"), "sender" : "me@example.com", "recipient" : "you@example.com", "timestamp" : ISODate("2017-10-28T04:03:21.468Z") }
{ "_id" : ObjectId("59f405d93e9fcadcbf2b1695"), "sender" : "me@example.com", "recipient" : "somebody@example.com", "timestamp" : ISODate("2017-10-28T04:21:45.573Z") }
{ "_id" : ObjectId("59f408413e9fcadcbf2b1699"), "sender" : "you@example.com", "recipient" : "somebody@example.com", "timestamp" : ISODate("2017-10-28T04:32:01.651Z") }
{ "_id" : ObjectId("59f408563e9fcadcbf2b169a"), "sender" : "you@example.com", "recipient" : "me@example.com", "timestamp" : ISODate("2017-10-28T04:32:22.376Z") }
{ "_id" : ObjectId("59f408763e9fcadcbf2b169b"), "sender" : "somebody@example.com", "recipient" : "you@example.com", "timestamp" : ISODate("2017-10-28T04:32:54.268Z") }
{ "_id" : ObjectId("59f4087e3e9fcadcbf2b169c"), "sender" : "somebody@example.com", "recipient" : "me@example.com", "timestamp" : ISODate("2017-10-28T04:33:02.615Z") }
我决定在sender
和recipient
上创建一个索引,并在timestamp
上添加一个附加键。这应该为您提供有关最常见用例的有效查询:
这给你带来最大的开销(一个索引中的一个字段)。
给出指数
> db.indextest.getIndices()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.indextest"
},
{
"v" : 1,
"key" : {
"recipient" : 1,
"timestamp" : 1
},
"name" : "recipient_1_timestamp_1",
"ns" : "test.indextest"
},
{
"v" : 1,
"key" : {
"sender" : 1,
"timestamp" : 1
},
"name" : "sender_1_timestamp_1",
"ns" : "test.indextest"
}
]
运行查询:
> db.indextest.find({$or:[{sender:"you@example.com"},{recipient:"you@example.com"}]}).sort({timestamp:1}).explain()
给出预期结果(为简洁起见编辑):
> db.indextest.find({$or:[{sender:"you@example.com"},{recipient:"you@example.com"}]}).sort({timestamp:1}).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.indextest",
"indexFilterSet" : false,
...
"winningPlan" : {
"stage" : "SUBPLAN",
"inputStage" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "SORT_MERGE",
"sortPattern" : {
"timestamp" : 1
},
"inputStages" : [
{
"stage" : "IXSCAN",
"keyPattern" : {
"recipient" : 1,
"timestamp" : 1
},
"indexName" : "recipient_1_timestamp_1",
"isMultiKey" : false,
...
"direction" : "forward",
"indexBounds" : {
"recipient" : [
"[\"you@example.com\", \"you@example.com\"]"
],
"timestamp" : [
"[MinKey, MaxKey]"
]
}
},
{
"stage" : "IXSCAN",
"keyPattern" : {
"sender" : 1,
"timestamp" : 1
},
"indexName" : "sender_1_timestamp_1",
"isMultiKey" : false,
...
"direction" : "forward",
"indexBounds" : {
"sender" : [
"[\"you@example.com\", \"you@example.com\"]"
],
"timestamp" : [
"[MinKey, MaxKey]"
]
}
}
]
}
}
},
"rejectedPlans" : [ ]
},
...
"ok" : 1
}
编辑:根据您的收藏大小,排序合并可能并不理想。