如何查找具有两个键值范围内的查询值的文档

时间:2015-02-27 18:29:21

标签: mongodb indexing geospatial compound-index

我在分析文字。那些文本有注释(例如“章节”,“风景”,......)。这些注释在我的MongoDB集合annotations中,例如

{
  start: 1,
  stop: 10000,
  type: chapter,
  details: {
    number: 1,
    title: "Where it all began"
  }
},
{
  start: 10001,
  stop: 20000,
  type: chapter,
  details: {
    number: 2,
    title: "Lovers"
  }
},
{
  start: 1,
  stop: 5000,
  type: scenery,
  details: {
    descr: "castle"
  }
},
{
  start: 5001,
  stop: 15000,
  type: scenery,
  details: {
    descr: "forest"
  }
}

挑战1 :对于文本中的给定位置,我想查找所有注释。例如,查询字符1234应该告诉我,

  • 它在第一章
  • 之内
  • 它发生在城堡里

挑战2 :我也想查询范围。例如,查询9800 to 10101字符应该告诉我它触及chapter 1chapter 2scenery forest

挑战3 :与挑战2 相比我只想匹配查询范围完全覆盖的那些注释。例如,查询9800 to 30000字符只应返回文档chapter 2

对于挑战1 ,我尝试使用$lt$gt。 e.g:

db.annotations.find({start: {$lt: 1234}, stop: {$gt: 1234}});

但我意识到,只使用了密钥start的索引,即使我有startstop的复合索引。有没有办法为我提到的三个问题创建更多适当的索引?

我很快就想到了地理空间索引,但我还没有使用它们。我也只需要它的一维版本。

1 个答案:

答案 0 :(得分:3)

对于挑战1 ,您使用的查询是合适的,但您可能希望$lte$gte包含在内。

db.annotations.find({ "start": { "$lt": 1234 }, "stop": { "$gt": 1234 }});

关于索引,它选择使用start上的索引而不是复合索引的原因与复合索引的树结构有关,Rob Moore在this answer中很好地解释了这一点。请注意,如果您使用hint(),它仍然可以使用复合索引,但查询优化器会更快地使用start上的索引,然后清除与该范围不匹配的结果stop条款。

对于挑战2 ,您只需要使用明确的$or子句来涵盖stopstart范围内start范围内的情况边界以及stopdb.annotations.find({ "$or": [ { "stop": { "$gte": 9800, "$lte": 10101 }}, { "start": { "$gte": 9800, "$lte": 10101 }}, { "start": { "$lt": 9800 }, "stop": { "$gt": 10101 }} ] }); 何时包含边界。

db.annotations.find({ "start": { "$gte": 9800 }, "stop": { "$lte": 30000 }});

对于挑战3 ,您可以使用与挑战1 中的查询非常类似的查询,但确保文档完全由给定范围覆盖。

{{1}}