我有大量的文档集合,通常来说,这些文档旨在存储数百万个文档。
通常,典型文档可能非常复杂且动态,但是每个文档中都应包含一些常量字段。这些字段包括:GlobalDeviceStatus
,ManualTests
,SemiAutomaticTests
,AutomaticTests
。所有这三种类型的测试均由对象数组表示。每个这样的对象可能包含很多字段,但是又有一些常量字段。它们是componentName
和componentTestStatus
。
{
"data": {
"globalDeviceStatus": false,
"qaOfficerID": 12121,
"ManualTests": [{
"componentName": "camera",
"componentTestStatus": true,
"x": 10
},
{
"componentName": "wifi",
"componentTestStatus": false,
"mnum": 711
}
],
"SemiAutomaticTests": [{
"componentName": "someComponent",
"componentTestStatus": true,
"someParameter": true
},
{
"componentName": "oneMoreComponent",
"componentTestStatus": false
}
],
"AutomaticTests": [{
"componentName": "anotherComponent",
"componentTestStatus": true
},
{
"componentName": "someVeryImportantComponent",
"componentTestStatus": false
}
]
},
"userID": 1
}
每个文档代表一个测试。如果GlobalDeviceStatus
的值为false
,则测试失败。这也意味着它的json至少应包含一个失败的组件(相反,GlobalDeviceStatus
等于true
的测试不包含很合乎逻辑的失败组件)。
我需要计算每个组件的故障数量,这就是我的输出,我需要这样的东西:
{
"componentName": 120,
"someOtherComponentName": 31
}
每个componentName只能属于一种测试类型。也就是说,如果在一个文档中进行了SemiAutomaticTests
测试,则无法迁移到另一文档中的AutomaticTests
。
要进行此类计算,我使用以下mongo管道:
COUNT_CRASHES = [
{
"$match": {
"$or": [{
"data.ManualTests.componentTestStatus": false
}, {
"data.AutomaticTests.componentTestStatus": false
}, {
"data.SemiAutomaticTests.componentTestStatus": false
}]
}
}, {
"$project": {
"tests": {
"$concatArrays": [{
"$filter": {
"input": "$data.ManualTests",
"as": "mt",
"cond": {
"$eq": ["$$mt.componentTestStatus", false]
}
}
}, {
"$filter": {
"input": "$data.AutomaticTests",
"as": "at",
"cond": {
"$eq": ["$$at.componentTestStatus", false]
}
}
}, {
"$filter": {
"input": "$data.SemiAutomaticTests",
"as": "st",
"cond": {
"$eq": ["$$st.componentTestStatus", false]
}
}
}]
}
}
}, {
"$unwind": "$tests"
}, {
"$group": {
"_id": "$tests.componentName",
"count": {
"$sum": 1
}
}
}
]
它以与上面指定的格式不同的格式返回数据,但并不重要,现在真正重要的是返回大约需要7秒,有时需要两倍的时间(〜14秒)。数据库中有35万个文档。
我想尽可能减少时间。
答案 0 :(得分:2)
除非您将文档重组为"ManualTests"
,"AutomaticTests"
和"SemiAutomaticTests"
成为字段值(而不是字段本身)(可能允许更精简的管道),否则您可能会需要创建三个这样的索引以加快$match
:
db.collection.createIndex({ "data.ManualTests.componentTestStatus": 1 })
db.collection.createIndex({ "data.AutomaticTests.componentTestStatus": 1 })
db.collection.createIndex({ "data.SemiautomaticTests.componentTestStatus": 1 })
还请注意,您的投影可以缩短为:
"$project": {
"tests": {
"$filter": {
"input": { "$concatArrays": [ "$data.ManualTests", "$data.AutomaticTests", "$data.SemiAutomaticTests" ] },
"as": "t",
"cond": {
"$eq": ["$$t.componentTestStatus", false]
}
}
}
}