sql >> Database >  >> NoSQL >> MongoDB

Documenten filteren op afstand opgeslagen in document met $near

Ervan uitgaande dat je al hebt uitgewerkt om te reageren op de gebeurtenisgegevens zoals je deze ontvangt en in de hand hebt (als je dat niet hebt gedaan, dan is dat een andere vraag, maar kijk naar aanpasbare cursors ), dan zou u een object met die gegevens moeten hebben waarmee u de gebruikers kunt ondervragen.

Dit is daarom niet het geval voor JavaScript-evaluatie met $where , omdat het geen toegang heeft tot de querygegevens die zijn geretourneerd door een $near operatie sowieso. Wat u in plaats daarvan wilt, is $geoNear uit het aggregatiekader. Dit kan de gevonden "afstand" vanaf de zoekopdracht projecteren, en in een later stadium de resultaten "filteren" tegen de door de gebruiker opgeslagen waarde voor de maximale afstand die ze willen reizen naar gepubliceerde evenementen:

// 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
  }
)

Nu moet u voorzichtig zijn met het geretourneerde getal, aangezien u lijkt op te slaan in "oude coördinatenparen" in plaats van GeoJSON, en de afstand die door deze bewerking wordt geretourneerd, in radialen is en niet in een standaardafstand. Dus aangenomen dat u in "mijlen" of "kilometers" opslaat op de gebruikersobjecten, dan moet u berekenen via de formule die wordt vermeld in de handleiding onder "Bereken afstanden met behulp van sferische geometrie" zoals vermeld in de handleiding.

De basis is dat je moet delen door de equatoriale straal van de aarde, ofwel 3.963,2 mijl of 6.378,1 kilometer om te converteren voor een vergelijking met wat je hebt opgeslagen.

Het alternatief is om in plaats daarvan op te slaan in GeoJSON, waar er een consistente meting in meters is.

Ervan uitgaande dat "kilometers" die "als" lijn wordt:

"if": { "$lt": [
    "$eventDistance",
    { "$divide": [ "$maxDistance", 6,378.1 ] }
 ]},

Om uw opgeslagen kilometerwaarde betrouwbaar te vergelijken met het resultaat in radialen.

Het andere om op te letten is dat $geoNear heeft een standaard "limiet" van 100 resultaten, dus u moet het "limiet" -argument daar "oppompen" tot het aantal voor verwachte gebruikers dat mogelijk overeenkomt. Je zou dit misschien zelfs willen doen in "bereiklijsten" van gebruikers-ID's voor een heel groot systeem, maar je kunt zo groot gaan als het geheugen toelaat binnen een enkele aggreatiebewerking en eventueel allowDiskUse waar nodig.

Als u die parameter niet afstemt, worden alleen de dichtstbijzijnde 100 resultaten ( standaard ) geretourneerd, wat misschien niet eens past bij uw volgende bewerking om die "dichtbij" de gebeurtenis te filteren om mee te beginnen. Gebruik echter je gezond verstand, want je hebt zeker een maximale afstand om potentiële gebruikers eruit te filteren, en dat kan ook aan de zoekopdracht worden toegevoegd.

Zoals gezegd, is het punt hier de afstand ter vergelijking terug te geven, dus de volgende stap is de $redact bewerking die de eigen "reisafstand" -waarde van de gebruiker kan vergelijken met de geretourneerde afstand vanaf de gebeurtenis. Het eindresultaat geeft alleen die gebruikers die binnen hun eigen afstandsbeperking van het evenement vallen, die in aanmerking komen voor melding.

Dat is de logica. U projecteert de afstand van de gebruiker tot de gebeurtenis en vergelijkt vervolgens met de door de gebruiker opgeslagen waarde voor welke afstand hij bereid is te reizen. Geen JavaScript en alle native operators die het vrij snel maken.

Ook zoals vermeld in de opties en het algemene commentaar, raad ik je echt aan een "2dsphere" -index te gebruiken voor nauwkeurige sferische afstandsberekening en om te converteren naar GeoJSON-opslag voor je coördinatenopslag in je database Objecten, omdat het beide algemene normen zijn die consistente resultaten produceren.



  1. Waarom kan ik geen record vinden op _id in mongodb

  2. Redis-interacties in javascript stoppen met Sinon

  3. Docker:map wijzigen waar docker-volumes worden opgeslagen

  4. mongodump van extern knooppunt - kan niet worden geverifieerd met het mechanisme SCRAM-SHA-256