Mongo显式/隐式AND表现不同

时间:2013-10-31 12:42:09

标签: c# mongodb indexing mongodb-indexes

基本问题:

以下两个查询是否相同?

(A) coll.find(k1:v1, k2:v2)             // List of fields
(B) coll.find($and: [{k1:v1}, {k2:v2}]) // $and the list of fields

如果是这样,为什么他们表现出不同的行为? (见下文)。如果没有,我怎样才能在C#中生成前者?

进一步讨论

我正在索引子文档中的字段。查询(A)正确使用索引但查询(B)没有。

以下是一些示例代码(它将直接在mongo控制台中运行):

{
  _id : Guid
  ..other stuff..
  Fields: { K1: V1, K2: V2 ...}
}

// Populate
db.test.insert({_id:1,Fields:{K1:123,K2:456}})
db.test.insert({_id:2,Fields:{K1:456,K2:123}})

// Index on fields of subdocument
db.test.ensureIndex({"Fields.K1": 1})
db.test.ensureIndex({"Fields.K2": 1})...

// Execute some queries
db.test.find({_id: {$lt: 20}, "$or": [{"Fields.K1": 123}, {"Fields.K2": 123}]}).explain()
db.test.find({$and: [{_id: {$lt: 20}}, {"$or": [{"Fields.K1": 123}, {"Fields.K2": 123}]}]}).explain()

第一个查询按预期使用索引。第二个没有。

问题摘要

  1. 两个find()查询是否等效?
  2. 如果是这样,为什么他们的行为会有所不同?如果没有,它们有何不同?
  3. 如何在没有$并使用C#驱动程序的情况下生成find()?
  4. 修改 --------

    对于记录,我在C#中使用的语法类似于:

    coll.find(Query.And([<id query>, <fields query>]));
    

    手动生成QueryDocument不起作用,因为它不能包含多个$或查询作为$或用作字典的键(我需要多个$或在我的实际查询中)。

2 个答案:

答案 0 :(得分:0)

我已经确定mongo文档在指出以逗号分隔的操作列表时提供隐式AND时有些误导。请进行以下查询:

// Returns 19 documents on sample data.
coll.find({{a simple query}, {an $or query}, {another $or query}})

在上面的例子中,我发现可以忽略其中一个$或查询。也就是说,3个查询没有与$和组合。提供明确的$并修复此问题:

// Returns 2 documents on the same sample data.
coll.find({$and: [{a simple query}, {an $or query}, {another $or query}]})

答案 1 :(得分:0)

是的,这两个查询功能相同。

关于执行此查询

db.test.find({
    _id: {$lt: 20}, 
    "$or": [{"Fields.K1": 123}, {"Fields.K2": 123}]
})

使用C#驱动程序,您可以使用:

var query = Query.And(Query.LT("_id", 20), 
                      Query.Or(Query.EQ("Fields.K1", 123), 
                               Query.EQ("Fields.K2", 123)));
var docs = test.Find(query);

即使使用Query.And,也会生成隐式AND查询,因为您可以看到是否检查了调用query.ToJson()的输出:

{ "_id" : { "$lt" : 20 }, "$or" : [{ "Fields.K1" : 123 }, { "Fields.K2" : 123 }] }

与原始查询匹配。

至于为什么一些显式的$and查询不使用等价的隐式AND查询所做的索引(或使用不同的索引,如本例所示),看起来Mongo的内部转换显式的能力并且隐含的是不完美的,这就是为什么你只想要使用$and的原因。