问题
I have this test
collection in my test
database.
[test] 2014-02-11 18:01:33.970 >>> db.test.find ();
{ "_id" : ObjectId("52faa8a695fa10cc7d2b7908"), "x" : 1 }
{ "_id" : ObjectId("52faa8ab95fa10cc7d2b7909"), "x" : 5 }
{ "_id" : ObjectId("52faa8ad95fa10cc7d2b790a"), "x" : 15 }
{ "_id" : ObjectId("52faa8b095fa10cc7d2b790b"), "x" : 25 }
{ "_id" : ObjectId("52faa8b795fa10cc7d2b790c"), "x" : [ 5, 25 ] }
If I create an ascending index on the x field with
[test] 2014-02-11 18:01:50.615 >>> db.test.createIndex({x : 1});
then this find query is working fine and returning the expected result:
[test] 2014-02-11 18:01:48.72 >>> db.test.find ( { x : {$gt: 10, $lt: 20} } ).min({x:10}).max({x:20});
{ "_id" : ObjectId("52faa8ad95fa10cc7d2b790a"), "x" : 15 }
[test] 2014-02-11 18:01:50.615 >>>
Buf if drop that ascending index, and then create a descending index with
[test] 2014-02-11 18:01:50.615 >>> db.test.createIndex({x : -1});
then the same find query is returning this error:
error: {
"$err" : "no index found for specified keyPattern: {} min: { x: 10.0 } max: { x: 20.0 }",
"code" : 10367
}
I was expecting that MongoDB would return the same document here:
{ "_id" : ObjectId("52faa8ad95fa10cc7d2b790a"), "x" : 15 }
This sounds illogical to me.
Why is that? Why is MongoDB not able to use that descending index on x?
create index
drop index
get indexes
回答1:
This works for me:
> db.h.insert({x:15})
> db.h.createIndex({x:-1})
> db.h.find().min({x:20}).max({x:10})
{ "_id" : ObjectId("52fb6930253ac3dcf43b27f5"), "x" : 15 }
Your index might have a problem with it.
The reason this works is because the index is the other way around.
Imagine you turn a list on its head, what min and max effectively say is get a range of that list with the min being 10 and max being 20. However that range no longer exists since the list is upside down. Instead the range must be reversed to match the list.
回答2:
To answer your question, it's not weird at all ( You seem to be asking lots of questions stating "weird" behavior ) if you actually look at what you are doing.
As you said you changed the order of you index to be descending. So lets look at the results of the query in stages:
> db.test.find ( { x : {$gt: 10, $lt: 20} } )
{ "_id" : ObjectId("52faa8b795fa10cc7d2b790c"), "x" : [ 5, 25 ] }
{ "_id" : ObjectId("52faa8ad95fa10cc7d2b790a"), "x" : 15 }
So there's your first result with the only documents matching your criteria. So let's look at the next stage and also the output of explain:
> db.test.find ( { x : {$gt: 10, $lt: 20} } ).min({x :10})
{ "_id" : ObjectId("52faa8b795fa10cc7d2b790c"), "x" : [ 5, 25 ] }
> db.test.find ( { x : {$gt: 10, $lt: 20} } ).min({x :10}).explain()
{
"cursor" : "BtreeCursor x_-1",
"isMultiKey" : true,
"n" : 1,
"nscannedObjects" : 3,
"nscanned" : 3,
"nscannedObjectsAllPlans" : 3,
"nscannedAllPlans" : 3,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"start" : {
"x" : 10
},
"end" : {
"x" : {
"$minElement" : 1
}
}
},
"server" : "ubuntu:27017"
}
Here we can see the result containing your row with the array value in x. This is the important part where you need to look at the indexBounds
as shown in the explain output. You can see that the bounds start at 10, which was your request, and end at the minimum result from from the array element. Which despite your lack of projection in the document, has actually given you the answer, 5.
So when you start of to modify again, looking for a result that is outside of the indexBounds, query goes boom. You messed up and asked for something that doesn't exist.
Now if you were expecting to get this back as a result:
{ "_id" : ObjectId("52faa8b795fa10cc7d2b790c"), "x" : [ 25 ] }
Well the answer is that things just do not work that way. As explained you already reduced the set in the first min operation. It's done.
来源:https://stackoverflow.com/questions/21715121/mongodb-descending-index-weird-behavior