First, some of the basics:
- Database Version: 3.4.2
- Shell Version: 3.4.3
- Document Structure: (many fields removed for clarity)
{
"data": {
"arrayOne": [
{
"ID": "[String1]",
"arrayTwo": [
{
"someNum": 23
},
{
"someNum": 28
}
]
},
{
"ID": "[String2]",
"arrayTwo": [
{
"someNum": 34
},
{
"someNum": 37
}
]
}
]
},
"metadata": {
// ...
}
}
- Compound Index: ( { "data.arrayOne.ID": 1, "data.arrayOne.arrayTwo.someNum": 1 } )
- Docs In Collection: 1009
I am trying to figure out how to quickly return results wherein a document within arrayOne contains a specific ID and contains at least one someNum value within a specified range.
The following query returns the correct 29 documents:
db.datacol.find( { "data.arrayOne": { $elemMatch: { arrayTwo: { $elemMatch: { someNum: { $gte: 20.47, $lt: 20.49 } } }, ID: "test_id_0" } } } );
However, it takes over 500 milliseconds to complete the search and it claims to examine all
1009 documents. From what I can see in the explain output, the indexBounds only properly match against the ID. See:
"indexBounds" : {
"[\"test_id_0\", \"test_id_0\"]"
],
"data.arrayOne.arrayTwo.someNum" : [
"[MinKey, MaxKey]"
]
}
Hinting that it should use the compound index does improve speed (~100ms) but it should be better.
To that end, I adjusted the query to the following as an experiment:
db.datacol.find( { "data.arrayOne": { $elemMatch: { "arrayTwo.someNum": { $elemMatch: { $gte: 20.47, $lt: 20.49 } }, ID: "test_id_0" } } } )
[You'll notice that the difference is that
someNum is now within the first
$elemMatch, rather than the second.]
This query returns 0 documents (verified via Cursor.count() and Cursor.hasNext()), but claims to examine 29 documents and has "nReturned: 29". It does this in ~10ms and reports the following bounds:
"indexBounds" : {
"[\"test_id_0\", \"test_id_0\"]"
],
"data.arrayOne.arrayTwo.someNum" : [
"[20.47, 20.49)"
]
}
Which is what I'd expect for this type of lookup (based on what I've understood from
this documentation). What's troublesome is the lack of returned data...
Could someone explain what's going on? Why does this newer version fail to actually return the 29 documents to the cursor? Why does moving the "someNum" field around as I did have such a large effect?