Collection c
has hundred thousands of documents, and every document has two fields (x
and y
). Below are some examples.
{ "_id" : ObjectId("53fecab45ae4ec5280a0736f"), "x" : 1, "y" : 1 }
{ "_id" : ObjectId("53fecab45ae4ec5280a07370"), "x" : 2, "y" : 1 }
{ "_id" : ObjectId("53fecab45ae4ec5280a07371"), "x" : 3, "y" : 1 }
{ "_id" : ObjectId("53fecab45ae4ec5280a07372"), "x" : 3, "y" : 2 }
{ "_id" : ObjectId("53fecab45ae4ec5280a07373"), "x" : 3, "y" : 3 }
{ "_id" : ObjectId("53fecab45ae4ec5280a07374"), "x" : 4, "y" : 2 }
{ "_id" : ObjectId("53fecab45ae4ec5280a07376"), "x" : 5, "y" : 1 }
{ "_id" : ObjectId("53fecab45ae4ec5280a07377"), "x" : 5, "y" : 3 }
{ "_id" : ObjectId("53fecab45ae4ec5280a07378"), "x" : 5, "y" : 5 }
{ "_id" : ObjectId("53fecab45ae4ec5280a07379"), "x" : 6, "y" : 2 }
{ "_id" : ObjectId("53fecab45ae4ec5280a0737a"), "x" : 6, "y" : 4 }
{ "_id" : ObjectId("53fecab45ae4ec5280a0737b"), "x" : 6, "y" : 4 }
{ "_id" : ObjectId("53fecab45ae4ec5280a0737c"), "x" : 7, "y" : 3 }
{ "_id" : ObjectId("53fecab45ae4ec5280a0737d"), "x" : 8, "y" : 8 }
{ "_id" : ObjectId("53fecab45ae4ec5280a0737e"), "x" : 9, "y" : 3 }
{ "_id" : ObjectId("53fecab45ae4ec5280a0737f"), "x" : 9, "y" : 1 }
{ "_id" : ObjectId("53fecab45ae4ec5280a07380"), "x" : 10, "y" : 11 }
The values of x
and y
is number type, but random.
Now I want to find no more than 3 documents whose values are least
but larger than or equal to
{x:5, y:3}.
Regulation to compare two documents by function:
int compareDocument(doc1, doc2) {
var result;
if (doc1.x > doc2.x) {
result = 1;
} else if (doc1.x == doc2.x) {
if (doc1.y > doc2.y) {
result = 1;
} else if (doc1.y == doc2.y) {
result = 0;
} else {
result = -1;
}
} else {
result = -1;
}
return result;
}
It must be executed in high performance. The method I have is:
> db.c.ensureIndex({x:1,y:1},{name:"asc"});
> db.c.find().hint("asc").min({x:5,y:3}).limit(3);
{ "_id" : ObjectId("53fecab45ae4ec5280a07377"), "x" : 5, "y" : 3 }
{ "_id" : ObjectId("53fecab45ae4ec5280a07378"), "x" : 5, "y" : 5 }
{ "_id" : ObjectId("53fecab45ae4ec5280a07379"), "x" : 6, "y" : 2 }
> db.c.find().hint("asc").min({x:5,y:3}).limit(3).explain();
{
"cursor" : "BtreeCursor asc",
"isMultiKey" : false,
"n" : 3,
"nscannedObjects" : 3,
"nscanned" : 3,
"nscannedObjectsAllPlans" : 3,
"nscannedAllPlans" : 3,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"start" : {
"x" : 5,
"y" : 3
},
"end" : {
"x" : {
"$maxElement" : 1
},
"y" : {
"$maxElement" : 1
}
}
},
"server" : "Mars-PC:27017"
}
Above only 3 documents scanned.
Again, I want to find no more than 3 documents whose values are largest
but less than or equal to
{x:5, y:3}.
Is it possible to do this by using above index asc
, or something else without creating new index, but keep high perforance?
I can't find it. What I can do is to create another similar index to fultill it.
> db.c.ensureIndex({x:-1, y:-1},{name:"desc"});
> db.c.find().hint("desc").min({x:5, y:3}).limit(3);
{ "_id" : ObjectId("53fecab45ae4ec5280a07377"), "x" : 5, "y" : 3 }
{ "_id" : ObjectId("53fecab45ae4ec5280a07376"), "x" : 5, "y" : 1 }
{ "_id" : ObjectId("53fecab45ae4ec5280a07374"), "x" : 4, "y" : 2 }
> db.c.find().hint("desc").min({x:5, y:3}).limit(3).explain();
{
"cursor" : "BtreeCursor desc",
"isMultiKey" : false,
"n" : 3,
"nscannedObjects" : 3,
"nscanned" : 3,
"nscannedObjectsAllPlans" : 3,
"nscannedAllPlans" : 3,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"start" : {
"x" : 5,
"y" : 3
},
"end" : {
"x" : {
"$minElement" : 1
},
"y" : {
"$minElement" : 1
}
}
},
"server" : "Mars-PC:27017"
}