2015-02-09 77 views
0

在我使用MongoDB时,我开始理解MongoDB索引的问题。问题是MongoDB索引有时不会强制查询两端边界。下面是在查询的数据库中,我遇到了一个输出:MongoDB索引边界约束

查询:

db.user.find({transaction:{$elemMatch:{product:"mobile", firstTransaction:{$gte:ISODate("2015-01-01"), $lt:ISODate("2015-01-02")}}}}).hint("transaction.product_1_transaction.firstTransaction_1").explain() 

输出:

"cursor" : "BtreeCursor transaction.firstTransaction_1_transaction.product_1", 
          "isMultiKey" : true, 
          "n" : 622, 
          "nscannedObjects" : 350931, 
          "nscanned" : 6188185, 
          "nscannedObjectsAllPlans" : 350931, 
          "nscannedAllPlans" : 6188185, 
          "scanAndOrder" : false, 
          "indexOnly" : false, 
          "nYields" : 235851, 
          "nChunkSkips" : 0, 
          "millis" : 407579, 
          "indexBounds" : { 
            "transaction.firstTransaction" : [ 
              [ 
                true, 
                ISODate("2015-01-02T00:00:00Z") 
              ] 
            ], 
            "transaction.product" : [ 
              [ 
                "mobile", 
                "mobile" 
              ] 
            ] 
          }, 

正如你可以看到在上面的例子为firstTransaction场一个绑定的末端真实而不是我提到的日期。我发现解决方法是min(),max()函数。我试过这些,但他们似乎没有使用嵌入式文档(事务是一个包含firstTransaction,产品等字段的子文档数组)。我收到以下错误:

查询:

db.user.find({transaction:{$elemMatch:{product:'mobile'}}}).min({transaction:{$elemMatch:{firstTransaction:ISODate("2015-01-01")}}}).max({transaction:{$elemMatch:{firstTransaction:ISODate("2015-01-02")}}}) 

输出:

planner returned error: unable to find relevant index for max/min query 

firstTransaction字段建立索引,虽然还有产品&其复合索引了。我不知道这里出了什么问题。

样品文件:

{ 
_id: UUID (indexed by default), 
name: string, 
dob: ISODate, 
addr: string, 
createdAt: ISODate (indexed), 
. 
. 
., 
transaction:[ 
{ 
firstTransaction: ISODate(indexed), 
lastTransaction: ISODate(indexed), 
amount: float, 
product: string (indexed), 
. 
. 
. 
},... 
], 
other sub documents... 
} 
+0

这将是相当有益的看到你的查询,而不仅仅是'explain'的输出...... – mnemosyn 2015-02-09 09:52:13

回答

1

这是正确的行为。你不能总是与$lte$gte的索引范围相交 - 有时它会给出不正确的结果。例如,考虑文档

{ "x" : [{ "a" : [4, 6] }] } 

本文档匹配查询

db.test.find({ "x" : { "$elemMatch" : { "a" : { "$gte" : 5, "$lte" : 5 } } } }); 

如果我们在{ "x.a" : 1 }定义一个指数,这两个指数范围是[5, infinity],和[-infinity, 5]。相交他们将给[5, 5]和使用此索引绑定将不匹配文档 - 不正确!

你能提供一个示例文档,并告诉我们更多关于你想要做什么的查询吗?使用上下文,可能有另一种方法来编写使用更紧密索引边界的查询。

+0

我明白了你的观点。尽管我的field-firstTransaction不是整个集合中的数组,我想限制两个索引的结束,以限制对文档的搜索以获得性能。我希望给出的示例文档有所帮助。 – harshad 2015-02-10 08:50:01

+0

这个示例显示索引边界行为涉及到一个数组 - 但重点是MongoDB不强制字段的类型,所以任何字段总是可以有一个数组值。因此,即使我们不允许在嵌入文档中存在数组字段的情况下与索引边界相交,我们仍然不允许与边界相交。 – wdberkeley 2015-02-10 14:59:41

+0

另外,您是否可以描述查询的目的,即它试图为应用程序实现的目标以及示例文档?您将无法实现您可能认为应以当前形式的查询应用的“完美”索引边界。 – wdberkeley 2015-02-10 15:01:07