MongoDBでgeo field only has 1 element
MongoDBではランダムソートをかけることができなくて、地理空間Indexを設定したフィールドから抽出することでランダムっぽくさせる、ということをやるわけですが。
ランダムで取り出す例
データを入れる
mongo> for(i=0; i<1000; i++) {
mongo> db.sandbox.insert({num:i, random:[Math.random(), Math.random()]});
mongo> }
地理空間Indexを作る
mongo> db.sandbox.ensureIndex({random:'2d'});
取り出す
mongo> db.sandbox.find({random: {$near: [Math.random(), Math.random()]}},{_id:0, num:1}).limit(10);
{ "num" : 867 }
{ "num" : 839 }
{ "num" : 631 }
{ "num" : 678 }
{ "num" : 559 }
{ "num" : 229 }
{ "num" : 395 }
{ "num" : 344 }
{ "num" : 60 }
{ "num" : 690 }
もう一回やると違う値を取って来れる
mongo> db.sandbox.find({random: {$near: [Math.random(), Math.random()]}},{_id:0, num:1}).limit(10);
{ "num" : 159 }
{ "num" : 962 }
{ "num" : 625 }
{ "num" : 803 }
{ "num" : 63 }
{ "num" : 403 }
{ "num" : 975 }
{ "num" : 287 }
{ "num" : 953 }
{ "num" : 932 }
ここまでは良い。
地理空間Indexを使うと$exists
の挙動がおかしくなる
$exists:0
が使えない
mongo> db.sandbox.count({random:{$exists:0}})
Mon Jul 28 18:54:35.436 count failed: {
"errmsg" : "exception: geo field only has 1 element :: caused by :: $exists: 0.0",
"code" : 13068,
"ok" : 0
} at src/mongo/shell/query.js:180
なぜかエラー。
一方、$exists:1
は使える
mongo> db.sandbox.count({random:{$exists:1}})
1000
そして$not
を付けても使える
mongo> db.sandbox.count({$not:{random:{$exists:1}}})
0
ほげぇ……
結論としては、バグでした
[SERVER-10917] Exists on geospatial fields - MongoDB
Affects Version/s: 2.4.6
-
Fix Version/s: 2.5.4
素直に最新の2.6系を使えればいいんだけど、Elasticsearchの件でバージョンアップできないので辛い。