sql >> Base de Datos >  >> NoSQL >> MongoDB

Geoespacial $ cerca del valor del campo del documento actual

Si es posible. Solo usa $geoNear en cambio. Cuidado con las capturas y lee atentamente.

Suponiendo que su intención es almacenar un campo como "travelDistance" para indicar en el documento que tales búsquedas deben ser "dentro" de la distancia suministrada desde el punto consultado para que sean válidas. Luego simplemente consultamos y evaluamos la condición con $redact :

db.collection.aggregate([
  { "$geoNear": {
    "near": { 
      "type": "Point",
      "coordinates": [x,y]
    },
    "spherical": true,
    "distanceField": "distance"
  }},
  { "$redact": {
    "$cond": {
      "if": { "$lte": [ "$distance", "$travelDistance" ] },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }}
])

El único inconveniente es que $geoNear como $near solo devolverá una cierta cantidad de documentos "cerca" en primer lugar. Puede ajustar eso con las opciones, pero a diferencia del formulario de consulta general, esto básicamente garantiza que los resultados eventuales devueltos serán menores que los números "más cercanos" especificados.

Mientras seas consciente de eso, entonces esto es perfectamente válido.

De hecho, es la forma general de lidiar con calificar lo que está "cerca" dentro de un radio.

También tenga en cuenta la "distancia" según cómo tenga almacenadas las coordenadas. Como pares de coordenadas heredados, las distancias estarán en radianes, por lo que probablemente necesitará hacer cálculos para convertirlos a kilómetros o millas.

Si usa GeoJSON, las distancias siempre se consideran en metros, como formato estándar.

Todas las notas de matemáticas están en la documentación.

N.B Lea el $geoNear cuidadosamente la documentación. Opciones como "spherical" son necesarios para "2dsphere" índices, como los que debería tener para las coordenadas del mundo real. También "limit" es posible que deba aplicarse para aumentar más allá del resultado predeterminado de 100 documentos, para un mayor recorte.

Como los comentarios mencionan spring mongo, entonces aquí está básicamente lo mismo hecho para eso:

Aggregation aggregation = newAggregation(
    new AggregationOperation() {
      @Override
      public DBObject toDBObject(AggregationOperationContext context) {
        return new BasicDBObject("$geoNear",
          new BasicDBObject(
            "near", new BasicDBObject(
              "type","Point")
              .append("coordinates", Arrays.asList(20,30))
            )
            .append("spherical",true)
            .append("distanceField","distance")
          );
        }
    },
    new AggregationOperation() {
      @Override
      public DBObject toDBObject(AggregationOperationContext context) {
        return new BasicDBObject("$redact",
          new BasicDBObject(
            "$cond", Arrays.asList(
               new BasicDBObject("$lte", Arrays.asList("$distance", "$travelDistance")),
               "$$KEEP",
               "$$PRUNE"
             )
          )
       );
     }
    }
);