0

距離がコレクションからの動的フィールドであるクエリを実行したいと思います。

コレクション内のエントリの例:

{
  name:'myName',
  location: {lat:10, lng:20},
  maximumDistance: 10
}
{
  name:'myName2',
  location: {lat:20, lng:20},
  maximumDistance: 100
}

私の目標は、この場所が特定の場所 (たとえば (10,10)) に近いが、計算された距離がこのmaximumDistanceフィールドより小さいすべての要素をこのコレクションから取得することです。

近くのクエリで maxDistance を定数値 (必要なすべての要素を取得するのに十分な高さ) に設定してから、Java コードでフィルターを実行できますが、SQL 指向すぎるクエリで実行することをお勧めします。

4

2 に答える 2

4

ドキュメントごとに距離を動的に設定できないため、通常のクエリではこれを行うことができません。MongoDB 2.4 の時点では、パイプラインの開始に geoNear オペレーターが追加されているため、集約フレームワークでこれを行うことができます。

最初の段階は、geonear コマンドに非常によく似た geoNear です。結果として、指定されたポイント (10,10) からドキュメントまでの距離も取得します。

第 2 段階では、project オペレーターを使用して maximumDistance フィールドと計算された geoNear 距離の差を追加する必要があります。

最後に、正のデルタ ((最大 - 距離) > 0) を持つドキュメントを照合します。

Asynchronous Java Driverのヘルパー クラスを使用したパイプラインを次に示します。

package example;

import static com.allanbank.mongodb.builder.AggregationProjectFields.include;
import static com.allanbank.mongodb.builder.QueryBuilder.where;
import static com.allanbank.mongodb.builder.expression.Expressions.field;
import static com.allanbank.mongodb.builder.expression.Expressions.set;
import static com.allanbank.mongodb.builder.expression.Expressions.subtract;

import com.allanbank.mongodb.bson.element.ArrayElement;
import com.allanbank.mongodb.builder.Aggregate;
import com.allanbank.mongodb.builder.AggregationGeoNear;
import com.allanbank.mongodb.builder.GeoJson;

public class AggregateGeoNear {
    public static void main(String[] args) {
        Aggregate aggregate = Aggregate
                .builder()
                .geoNear(
                        AggregationGeoNear.builder()
                                .location(GeoJson.p(10, 10))
                                .distanceField("distance"))
                .project(
                        include("name", "location", "maximumDistance"),
                        set("delta",
                                subtract(field("maximumDistance"),
                                        field("distance"))))
                .match(where("delta").greaterThanOrEqualTo(0)).build();

        System.out
                .println(new ArrayElement("pipeline", aggregate.getPipeline()));
    }
}

そして、パイプラインが作成されます:

pipeline : [
  {
    '$geoNear' : {
      near : [
        10, 
        10
      ],
      distanceField : 'distance',
      spherical : false,
      uniqueDocs : true
    }
  }, 
  {
    '$project' : {
      name : 1,
      location : 1,
      maximumDistance : 1,
      delta : {
        '$subtract' : [
          '$maximumDistance', 
          '$distance'
        ]
      }
    }
  }, 
  {
    '$match' : {
      delta : { '$gte' : 0 }
    }
  }
]

HTH - ロブ。

PS 上記のビルダーは、ドライバーの 1.2.0 バージョンのプレリリースを使用しています。コードは、私が入力しているビルド マトリックスを通過しており、2013 年 3 月 22 日金曜日までにリリースされる予定です。

于 2013-03-21T03:20:38.867 に答える
1

Spring Data でそれを解決する方法については、投影内に maxDistance フィールド名を含めることが必須であるため、新しい GeoNearOperation 実装を構築することで解決しました。

public class GeoNearOperation2  implements AggregationOperation  {

private NearQuery nearQuery;

public GeoNearOperation2(NearQuery nearQuery) {
    this.nearQuery = nearQuery;
}

public DBObject toDBObject(AggregationOperationContext context) {
    DBObject dbObject = context.getMappedObject(nearQuery.toDBObject());
    dbObject.put("distanceField", "distance");
    return new BasicDBObject("$geoNear",dbObject);
}

}
于 2014-05-26T13:02:46.520 に答える