sql >> Database teknologi >  >> NoSQL >> MongoDB

Filtrer dokumenter efter afstand gemt i dokument med $near

Forudsat at du allerede har arbejdet på at handle på begivenhedsdataene, når du modtager dem og har dem i hånden (hvis du ikke har det, så er det et andet spørgsmål, men se på tailable cursorer ), så skulle du have et objekt med disse data, som du kan forespørge brugerne med.

Dette er derfor ikke et tilfælde for JavaScript-evaluering med $where , da den ikke kan få adgang til de forespørgselsdata, der returneres fra en $near operation alligevel. Det, du ønsker i stedet, er $geoNear fra aggregeringsrammen. Dette kan projicere "afstanden" fundet fra forespørgslen og tillade et senere trin at "filtrere" resultaterne mod den brugerlagrede værdi for den maksimale afstand, de ønsker at rejse til offentliggjorte begivenheder:

// 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 skal du være forsigtig med det returnerede nummer, da du ser ud til at gemme i "legacy koordinatpar" i stedet for GeoJSON, så vil den returnerede afstand fra denne operation være i radianer og ikke en standardafstand. Så hvis du antager, at du gemmer i "miles" eller "kilometer" på brugerobjekterne, så skal du beregne via formlen nævnt i manualen under "Beregn afstande ved hjælp af sfærisk geometri" som nævnt i manualen.

Det grundlæggende er, at du skal dividere med jordens ækvatoriale radius, enten 3.963,2 miles eller 6.378,1 kilometer for at konvertere til en sammenligning med det, du har gemt.

Alternativet er at gemme i GeoJSON i stedet, hvor der er en ensartet måling i meter.

Hvis vi antager "kilometer", bliver "hvis"-linjen:

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

For pålideligt at sammenligne din gemte kilometerværdi med det returnerede radianresultat.

Den anden ting, du skal være opmærksom på, er at $geoNear har en standard "grænse" på 100 resultater, så du skal "pumpe" "grænse"-argumentet der til det antal, som forventede brugere muligvis matcher. Du vil måske endda gøre dette i "range lists" over bruger-id'er for et virkelig stort system, men du kan gå så stort som hukommelsen tillader inden for en enkelt aggregeringsoperation og eventuelt tilføje allowDiskUse hvor det er nødvendigt.

Hvis du ikke justerer denne parameter, vil kun de nærmeste 100 resultater (standard) blive returneret, hvilket måske ikke engang passer til din næste operation med at filtrere dem "nært på" begivenheden til at starte med. Brug dog sund fornuft, da du helt sikkert har en maksimal afstand til endda at bortfiltrere potentielle brugere, og det kan også føjes til forespørgslen.

Som nævnt er pointen her at returnere afstanden til sammenligning, så næste trin er $redact operation, som kan tilpasse brugerens egen "rejsedistance" værdi mod den returnerede distance fra begivenheden. Slutresultatet giver kun de brugere, der falder inden for deres egen afstandsbegrænsning fra begivenheden, som vil kvalificere sig til underretning.

Det er logikken. Du projicerer afstanden fra brugeren til begivenheden og sammenligner derefter med den brugerlagrede værdi for, hvilken afstand de er parate til at rejse. Ingen JavaScript, og alle native operatorer, der gør det ret hurtigt.

Også som nævnt i mulighederne og den generelle kommentar, foreslår jeg virkelig, at du bruger et "2dsphere"-indeks til nøjagtig sfærisk afstandsberegning samt konvertering til GeoJSON-lagring til din koordinatlagring i dine databaseobjekter, da de begge er generelle standarder, der producere ensartede resultater.



  1. Skub værdier ind i matrix af mongodb-database gennem (sails js) vandlinje

  2. Advarsel om forbindelse til MongoDB med en nodeserver

  3. Golang GraphQL MongoDB Kæmper med at få dato og id ud af databasen

  4. Ved oprettelse af den første admin-bruger på mongdb-klyngen får fejlmeddelelsen ikke kunne tilføje bruger:ikke autoriseret på admin til at udføre kommandoen