イベントデータを受け取り、手元に置いたときに、イベントデータに基づいて行動するようにすでに取り組んでいると仮定します(そうでない場合は、別の質問ですが、テーラブルカーソル )、次に、ユーザーにクエリを実行するためのデータを含むオブジェクトが必要です。
したがって、これは $where<を使用したJavaScript評価には当てはまりません。 / code>
、 $nearから返されたクエリデータにアクセスできないため
とにかく操作。代わりに必要なのは、 $ geoNear
>
集約フレームワークから。これにより、クエリから見つかった「距離」を予測し、後の段階で、公開されたイベントまで移動したい最大距離について、ユーザーが保存した値に対して結果を「フィルタリング」できるようになります。
// Represent retrieved event data
var eventData = {
eventLocation: {
latlong: [long,lat]
}
};
// Find users near that event within their stored distance
User.aggregate(
[
{ "$geoNear": {
"near": {
"type": "Point",
"coordinates": eventData.eventLocation.latlong
},
"distanceField": "eventDistance",
"limit": 100000,
"spherical": true
}},
{ "$redact": {
"$cond": {
"if": { "$lt": [ "$eventDistance", "$maxDistance" ] },
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
]
function(err,results) {
// Work with results in here
}
)
ここで、返される数値に注意する必要があります。GeoJSONではなく「レガシー座標ペア」で格納しているように見えるため、この操作から返される距離はラジアンであり、標準の距離ではありません。したがって、ユーザーオブジェクトに「マイル」または「キロメートル」で格納していると仮定すると、「球面幾何学を使用して距離を計算する」 マニュアルに記載されているように。
基本的には、地球の赤道半径で割る必要があります。保存したものと比較するために変換するには、3,963.2マイルまたは6,378.1キロメートルのいずれかです。
別の方法は、代わりにGeoJSONに保存することです。ここでは、メートル単位で一貫した測定が行われます。
「キロメートル」を「if」の線が次のようになると仮定します。
"if": { "$lt": [
"$eventDistance",
{ "$divide": [ "$maxDistance", 6,378.1 ] }
]},
保存されたキロメートル値を、取得されたラジアン結果と確実に比較するため。
もう1つ注意すべき点は、 $ geoNear
デフォルトの「制限」は100件であるため、予想されるユーザーが一致する可能性がある数に「制限」引数を「ポンプアップ」する必要があります。非常に大規模なシステムのユーザーIDの「範囲リスト」でこれを実行することもできますが、1回の集計操作でメモリが許す限り大きくして、 allowDiskUse
必要に応じて。
そのパラメータを調整しないと、最も近い100個の結果(デフォルト)のみが返されます。これは、最初にイベントの「近く」をフィルタリングする次の操作にさえ適さない可能性があります。ただし、常識を働かせてください。潜在的なユーザーを除外するための最大距離が確実にあり、それをクエリに追加することもできます。
前述のように、ここでのポイントは比較のために距離を返すことなので、次の段階は $ redact
イベントから返された距離に対してユーザー自身の「移動距離」値を適合させることができる操作。最終結果は、通知の対象となるイベントから自分の距離内にあるユーザーのみを提供します。
それが論理です。ユーザーからイベントまでの距離を予測し、ユーザーが保存した値と比較して、ユーザーが移動する準備ができている距離を確認します。 JavaScriptはなく、JavaScriptを非常に高速にするすべてのネイティブ演算子。
また、オプションと一般的な解説に記載されているように、正確な球面距離の計算には「2dsphere」インデックスを使用し、データベースオブジェクトの座標ストレージにはGeoJSONストレージに変換することをお勧めします。どちらも一般的な標準です。一貫した結果を生み出します。