2

私はMongoDBコレクションを持っています。ここには次の構造のドキュメントがあります

{
   ...
   distanceDeviation: 2.0,

   loc: [
      [24.77, 67.5],
      [24.78, 67.6],
      [24.79, 67.7],
      [24.80, 67.8],
      ...
   ]
   ...
}

このコレクションにジオインデックスを付けています(ensureIndexを使用loc)。

2つのポイントを送信すると、Mongoがコレクションからドキュメントを返すクエリが必要です。このドキュメントには両方のポイントが配列に含まれています。loc

私は次のよう$withinに固定$radiusパラメータを使用してそれを行うことができました:

{
    "$and": [
                {
                    "loc": {
                        "$within": {
                            "$center": [
                                [
                                    24.812640000000002,
                                    67.01985
                                ],
                                1.5
                            ]
                        }
                    }
                },
                {
                    "loc": {
                        "$within": {
                            "$center": [
                                [
                                    24.900070000000003,
                                    67.16828000000001
                                ],
                                1.5
                            ]
                        }
                    }
                }
            ]
}

ただし、radiusとして指定する代わりに、このドキュメントの一部である属性distanceDeviationが使用される1.5ように指定したい場合。

とにかくこれを達成するためにできればなしでありますか$where。そうでない場合は、どうすればそれを行うことができますか$where

4

1 に答える 1

0

少しぎこちなくても、ジョブaggregate()とその$geoNearオペレーターを使用する可能性があります。厄介なことに、aggregate は 1 つしか許可しないため$geoNear、それは集約パイプラインの一番上になければなりません。したがって、2 つの集計を行ってから結果をマージする必要があります。

アイデア: $geoNear「loc」ルートの各ポイントから特定のポイントまでの距離を返します。次に、最小距離を取得し、$condそれが範囲内にあるかどうかをオペレーターでテストし、範囲内にdistanceDeviationある場合はドキュメントを返すことができます。

結果は、最初のポイントに一致するドキュメントの配列です。次に、他のポイントに対して操作を繰り返し、2 つの配列をマージして、両方の配列に表示されるドキュメントのリストを作成します。

これがどのように機能するかです(読みやすくするために、他の座標を使用しました)

db.xx.drop();
db.xx.insert( { distanceDeviation: 2.0, loc: [ [0,0], [10,-10], [20,10], [30,0] ] } );
db.xx.insert( { distanceDeviation: 0.1, loc: [ [0,0], [10,-10], [20,10], [30,0] ] } );
db.xx.ensureIndex({ loc: "2d" });
db.xx.find();

// points to query:
pointA = [1,1]
pointB = [21,11]

aggA = db.xx.aggregate([
    { $geoNear: { near: pointA, distanceField: "dist" } },
    { $group: { _id: { oid: "$_id", dev: "$distanceDeviation" }, min: { $min: "$dist" } } },
    { $project: { oid: "$_id.oid", isNear: { $cond: [ { $lt: [ "$min", "$_id.dev" ] }, 1, 0 ] }, _id: 0 } },
    { $match: { isNear: 1 } },
]);


aggB = db.xx.aggregate([
    { $geoNear: { near: pointB, distanceField: "dist" } },
    { $group: { _id: { oid: "$_id", dev: "$distanceDeviation" }, min: { $min: "$dist" } } },
    { $project: { oid: "$_id.oid", isNear: { $cond: [ { $lt: [ "$min", "$_id.dev" ] }, 1, 0 ] }, _id: 0 } },
    { $match: { isNear: 1 } },
]);

print("\nObjects with point near route:\n");
aggA.result.forEach( function( a ) {
    aggB.result.forEach( function( b ) {
        if ( a.oid.toString == b.oid.toString ) { print( a.oid ) };        
    });
    // Note: this can be optimised        
});

結果は次のとおりです。

> db.xx.find()
{ "_id" : ObjectId("5161da88ab49f42c329f4228"), "distanceDeviation" : 2, "loc" : [ [ 0, 0 ], [ 10, -10 ], [ 20, 10 ], [ 30, 0 ] ] }
{ "_id" : ObjectId("5161da88ab49f42c329f4229"), "distanceDeviation" : 0.1, "loc" : [ [ 0, 0 ], [ 10, -10 ], [ 20, 10 ], [ 30, 0 ] ] }

>> // run the aggregates

Objects with point near route:

ObjectId("5161da88ab49f42c329f4228")

もう 1 つの完全に異なるアプローチは、距離 "distanceDeviation" でルートの周りに閉じた多角形を "描画" し、これもドキュメントに保存することです。これにより、$within: $polygon(円内での検索と同様に) 検索が可能になり、ルートに近いが構成ポイントの 1 つに必ずしも近いとは限らないポイントに対しても一致が返されます。

aggregate()$geoNear$polygonの詳細については、マニュアルを参照してください。

于 2013-04-07T21:19:57.240 に答える