如果未使用正确的索引,MongoDB查询将失败

时间:2018-06-21 15:29:17

标签: mongodb

Mongo收集为例

{ 
  entityId: 43212
  jobExists: true,
  value: 75,
  ...
  parent: "Mogli"
}
{
  entityId: 12435
  jobExists: false,
  reasonForNonExistence: "Too many arguments",
  value: 97,
  ...
  parent: "Baba"
}

等...

请注意,仅具有jobExists:false的记录还包含另一个名为reasonForNonExistence 的字段,而其他记录则没有。 数据库中大约有1100万条记录。

在EntityId和jobExists字段上存在索引。

查询非常复杂的查询时,前两个条件为“ entityId:xxx”和“ jobExists:false”,其余查询将在“ reasonForNonExistence”字段中检查条件。

大多数情况下,查询成功并且一切正常,但是,当mongo选择NOT时,不使用实体ID和jobExists上的索引,他实际上也尝试检查其他条件,从而导致字段原因ForNonExistence出现未定义的异常

我的问题是,如果mongo显然应该甚至检查其余条件,因为前2个可以将文档过滤掉,为什么mongo如果不使用索引就会失败?

如何避免这种情况并使之正常工作? (我知道检查查询中是否定义了字段的选项……只是想看看是否有更好的方法)

谢谢。

这是由我们的代码创建并运行的查询:

db.reports.find(
{"$and":
[
    {"$and":
    [
        {"jobExists":false},
        {"entityId":
            {"$in":["878"]}
        },
        {"$or":
        [
            {"entries":{"$exists":false}},
            {"entries":{"$size":0}},
            {"entries":{"$elemMatch":{"invoicedAt":{"$exists":false}}}},
            {"entries":{"$elemMatch":
            {"$and":
            [
                {"invoicedAt":{"$lte":{"$date":1529366400000}}},
                {"invoicedAt":{"$gte":{"$date":1483228800000}}}
            ]}
            }}
        ]},
        {"$or":
        [
            {"entries":{"$exists":false}},
            {"entries":{"$size":0}},
            {"entries":{"$elemMatch":{"country":{"$exists":false}}}},
            {"entries":{"$elemMatch":{"country":
            {"$in":["AT","BE","BG","HR","CY","CZ","DK","EE","FI","FR","DE","GR","HU","IE","IT","LV","LT","LU","MT","NL","PL","PT","RO","SK","SI","ES","SE","GB","NO","CH","RS"]}}}}
        ]}
    ]},
    {"$or":
    [
        {"companyInfo.country":{"$exists":false}},
        {"companyInfo.vatRegistrations":{"$exists":false}},
        {"entries":{"$exists":false}},
        {"entries":{"$size":0}},
        {"entries":{"$elemMatch":{"country":{"$exists":false}}}},
        {"entries":{"$elemMatch":{"invoicedAt":{"$exists":false}}}},
        {"$and":
        [
            {"companyInfo.country":{"$exists":true}},
            {"entries.0":{"$exists":true}},
            {"$where":"function() {  
                function foreign(entry) { 
                return obj.companyInfo != null && entry.country != null && obj.companyInfo.country != entry.country; 
                }  
                function vatReg(entry) { 
                var vatRegs = obj.companyInfo.vatRegistrations == null ? [] : obj.companyInfo.vatRegistrations;    
                return vatRegs.some(function(reg) {  
                return entry.country == reg.country && (
                reg.registrationDate.getTime() == ISODate(\"1970-01-01\").getTime() &&    
                reg.registrationEndDate.getTime() == ISODate(\"3000-01-01\").getTime() 
                || (
                entry.invoicedAt != null && entry.invoicedAt.getTime() >= reg.registrationDate.getTime() && 
                entry.invoicedAt.getTime() <= reg.registrationEndDate.getTime()    )  
                );
                });  
                }  
                function check(entry) { return foreign(entry) && !vatReg(entry); }  
                return obj.entries.some(check);}"
            }
        ]}
    ]}
]
}).count();

我知道很难追踪。 请注意,前两个条件位于“ jobExist”字段和“ entityId”上 如果首先检查这两个条件(例如是否在jobExists和entityId上使用此索引),则所有其余文档都存在“ registrationEndDate”字段,因此“ where”子句下的查询可以工作。

但是如果选择了另一个索引,由于某种原因,它就像在运行2个条件之前尝试运行“ where”查询,以便它扫描不具有registrationEndDate字段并失败的文档,但出现以下异常:

  

“ exception”:“ reactivemongo.api.commands.LastError:   DatabaseException ['TypeError:reg.registrationEndDate未定义   :\ nvatReg / <@:12:1 \ nvatReg @:9:1 \ ncheck @:22:31 \ n @:24:10 \ n'(代码=   139)] \ n“}

0 个答案:

没有答案