Josh Liptzin
Josh Liptzin

Reputation: 796

Mongodb $nearSphere with skip and limit in 2.4.3 vs. 2.6.1

I've been using mongodb 2.4.3 for a social networking application which returns profiles based on distance to the caller. I used the $nearSphere operator as follows:

db.profiles.find({loc: {$nearSphere: <lon, lat>}} ...).skip(0).limit(100);

I know that the $nearSphere operator only returns 100 results, however it does sort the result set by distance which is what I need, and since my application pages results in multiples of 100 anyway, I was able to iterate through the profiles list by distance just by incrementing the skip value as follows:

db.profiles.find({loc: {$nearSphere: <lon, lat>}} ...).skip(100).limit(100);
db.profiles.find({loc: {$nearSphere: <lon, lat>}} ...).skip(200).limit(100);
db.profiles.find({loc: {$nearSphere: <lon, lat>}} ...).skip(300).limit(100);

This has been working great for about a year. I recently upgraded to 2.6.1, and noticed that now, no matter what skip value I pass it, only the first 100 results are returned. I've since had to downgrade back to v2.4.3 in order to get this functionality back.

My question is, is this behavior a bug in 2.4.3, or a bug in 2.6.1? The docs don't mention this change as far as I can tell. If a bug in 2.4.3 that I happened to be taking advantage of, what's the best way to adapt while keeping the same functionality? Thanks!

Upvotes: 1

Views: 288

Answers (1)

surui
surui

Reputation: 1542

the 100 limit you state is only for the '2d' index, so I guess you're using the '2d' index. from what I tested in version 2.6.3 (and 2.6.0, before I updated to the latest) it seems like there is a bug where the limit of this specific query doesn't take into account the the skip, so if you skip by 100 you should limit by 100 + limit.

to reproduce (in mongo client):

db.test.drop();
db.test.ensureIndex({point: "2d"});
for (var i = 0; i < 200; ++i) { 
  db.test.insert({point:[1,2]});
}
db.test.insert({point:[1,2.01]});
db.test.find({point: {$nearSphere: [1,2]}}).skip(200).limit(201);

returns:

{ "_id" : ObjectId("53a476c6c83c83ebdd121038"), "point" : [ 1, 2.01 ] }

when you

db.test.find({point: {$nearSphere: [1,2]}}).skip(200).limit(1);

there's nothing.

for comparison, when you

db.test.find({}).skip(200).limit(1)

it returns

{ "_id" : ObjectId("53a476c6c83c83ebdd121038"), "point" : [ 1, 2.01 ] }

for '2dsphere' it works as you would expect.

Upvotes: 3

Related Questions