‫Welcome back after a long lecture
‫where we searched for tour documents
‫within a certain distance
‫from a certain point using geospatial queries.
‫Now in this lecture, let's use geospatial aggregation
‫in order to calculate distances
‫to all the tours from a certain point.
‫So just like before let's actually start
‫by defining the route so that we know
‫which data we're going to be working with.
‫So router.route;
‫at this time I'm gonna call it simply distances,
‫and then the data that we need
‫is the latitude and the longitude
‫of the point where the user currently is,
‫so in our previous example that was LA,
‫and then let's also allow the user
‫again to specify the unit.
‫Then here, the route handler function.
‫Now this time here,
‫we do not need the distance parameter,
‫as we had it right here,
‫because we're not gonna be searching for a certain radius.
‫We're really gonna calculate the distance
‫from a certain point to all the tours
‫that we have in our collection.
‫So the handler is at tourController,
‫and it's gonna be called getDistances.
‫We don't have that yet, and so let's create it.
‫CatchAsync, and then of course
‫mark the function as async as well
‫because we already know that we're gonna use
‫the aggregation pipeline, and so by the time
‫we're gonna be using a wait.
‫The beginning of this function is actually quite similar
‫to the getToursWithin one, and so let's go ahead
‫and just copy all of this code.
‫We have some similar units, then we also need to get
‫the latitude and longitude,
‫and we also need to create this error
‫in case there is no latitude or no longitude.
‫This one here does not apply,
‫and also we don't have the distance.
‫So let's now do the actual calculation.
‫Just like before in order to do calculations
‫we always use the aggregation pipeline.
‫And remember, that is called on the model itself.
‫So Tour.aggregate.
‫Then let's await that, and save it
‫into the distances variable.
‫So then here, remember, we passed in an array
‫with all the stages of the aggregation pipeline
‫that we want to define.
‫Now for geospatial aggregation,
‫there's actually only one single stage,
‫and that's called geoNear, so this one.
‫Again, this is the only geospatial
‫aggregation pipeline stage that actually exists.
‫This one always needs to be the first one in the pipeline.
‫So keep that in mind that geoNear
‫always needs to be the first stage.
‫Something else that's also very important to note
‫about geoNear is that it requires
‫that at least one of our fields
‫contains a geospatial index.
‫Actually we already did that before,
‫so let's again take a look.
‫Our start location already has
‫this 2dsphere geospatial index on it.
‫Since we're using this startLocation
‫in order to calculate the distances,
‫well, that's then perfect.
‫If there's only one field with a geospatial index
‫then this geoNear stage here will automatically use
‫that index in order to perform the calculation.
‫But if you have multiple fields with geospatial indexes
‫then you need to use the keys parameter
‫in order to define the field
‫that you want to use for calculations.
‫So keep that in mind, but again,
‫in this case we only have one field,
‫and so automatically that startLocation field
‫is going to be used for doing these calculations.
‫So, what do we need to pass into geoNear?
‫Well, first we need to specify the near property,
‫and near is the point from which to calculate the distances.
‫So all the distances will be calculated from this point
‫that we define here, and then all the start locations.
‫So this near point here is of course
‫the point that we pass into this function
‫with this latitude and longitude.
‫Now we need to specify this point here as geojson,
‫so that's just like we did it before,
‫where we need to specify the type as Point,
‫and then specify the coordinates property.
‫And as always the first coordinate here is the longitude,
‫and then the second one, the latitude.
‫And let's multiply both of them by one,
‫simply to convert it to numbers.
‫So this is the first mandatory field, near,
‫and the second one is the distance field property.
‫So, distanceField, and so this is the name
‫of the field that will be created
‫and where all the calculated distances will be stored.
‫So let's simply call this one distance.
‫Actually, that's it.
‫That's all the fields that are mandatory
‫in this geoNear stage.
‫And of course, we can add other stages here,
‫and we're actually going to do that a bit later,
‫but for now all I want to do
‫is to really see the results of this working.
‫Let's again copy this a result here,
‫thus sending these results, and here,
‫let's then send the distances,
‫and also this one we don't need.
‫So, we're ready to start.
‫Keep in mind that at this point we didn't use the unit,
‫but don't worry about that.
‫We're gonna do that in a second,
‫but again, first I really want to see this working.
‫Remember that the route is now distances,
‫so let's just copy this one here.
‫Actually, I will save it also,
‫so into the tours.
‫Let's say get tours within radius.
‫This here is called distances,
‫and we do not have this and also not this.
‫So just the coordinates, and then again the unit.
‫Let's take a look, and we will now get this error.
‫Remember how we said that geoNear
‫always needs to be the first stage in a pipeline,
‫but if you now take a look at the code
‫you might think that actually our geoNear stage
‫is currently the first stage of our pipeline.
‫Because right here, it actually looks like it is, right?
‫There's nothing before this, and so why do we get this error
‫that geoNear is not the first stage in the pipeline?
‫Actually it took me a bit of time to figure this out
‫because this has something to do with a piece of code
‫that we wrote a long time ago.
‫That's here in the tour model,
‫and if we go down here, I think.
‫Right here, we have this aggregation middleware,
‫and remember that what this did is to actually always add
‫this match stage here before all the other stages,
‫and actually we have this console.log here
‫and so indeed you can actually see
‫the entire pipeline down here.
‫And so you see that we first have the match,
‫and then the geoNear phase here,
‫actually only as the second stage.
‫So it actually makes sense that we get that error.
‫Now we could go ahead and change this middleware here
‫and say that if geoNear is the first operator
‫in the pipeline, then simply do not do this here.
‫But that's a bit too much work for this use case,
‫so all I'm gonna do is to get rid of this middleware.
‫So give this a save, and now let's try it again.
‫Now we get our tours, and now it should have
‫that distance field on them.
‫So let's search for that, and indeed here it goes.
‫So distance, and then this huge number here.
‫It is this big number,
‫because actually it's calculated in meters,
‫so this result comes in meters,
‫so let's first of all convert this one to kilometers.
‫Later on we will then also convert it to miles,
‫because remember we specified the unit to miles,
‫but for now the easiest solution
‫is to actually convert it to kilometers,
‫because all we have to do for that
‫is to just divide it by 1000.
‫And then also what I want to do
‫is to only really get the distances,
‫and the name of the tours.
‫So get rid of all the other clutter that we have here
‫and really only focus on the distances themselves.
‫For that, as you might remember,
‫we can use the project stage.
‫So let's add that here as the second stage.
‫So project, and then basically the names
‫of the fields that we want to keep.
‫So that's the distance, and so we set that one to one,
‫saying that we want to keep it, and then also the name
‫so that we actually know what tour we're talking about.
‫With that we get rid of all the other data,
‫and now let's basically divide the distance by 1000
‫in order to convert these meters to kilometers.
‫Actually, it's very easy to do that,
‫because in a geoNear stage we can actually specify
‫the distance multiplier property.
‫So distanceMultiplier, and so here we can specify a number
‫which is then going to be multiplied with all the distances.
‫Here we specify 0.001, and so that is exactly the same
‫as dividing by 1000.
‫So let's test our result here now.
‫And that calculation apparently takes some time,
‫but now here we go.
‫So now you get this nice result here in kilometers.
‫As you see the Sports Lover is the closest tour
‫to the location in Los Angeles that we marked.
‫So it's only 64 kilometers away,
‫which should be something like 40 miles.
‫But again, we're going to do that conversion in a second.
‫For now, I just want to go back to that map and compass
‫and see if this actually makes sense.
‫So we're still here,
‫and we still have our start locations map.
‫Now the problem here
‫is that we actually cannot really click
‫on any of these points and see what they are.
‫But let's just draw a quick circle here again
‫just to see which are the closest tours,
‫and if they match the ones in our output.
‫So it's kind of here, I believe,
‫and so let's include these five tours here.
‫So their names are The Park Camper, Snow Adventurer,
‫Wine Taster, Sports Lover and Star Gazer,
‫and so now when we come here,
‫these ones are actually the first five ones.
‫Sports Lover, Park Camper, Wine Taster,
‫Star Gazer and Snow Adventurer.
‫So that one that's really close is the Sports Lover,
‫and then the next one is the Park Camper
‫and the Wine Taster.
‫This one here is going to be the Park Camper,
‫which I believe starts in Las Vegas,
‫so that makes sense,
‫and then a third one is here,
‫The Wine Taster close to San Francisco.
‫So that distance of 800 kilometers I think,
‫or what was that?
‫Yeah, 600 kilometers, that actually makes kind of sense.
‫So, something close to 400 miles here.
‫And speaking of miles, let's actually do
‫that conversion right now.
‫Let's do something similar to what we did before,
‫so testing for the unit.
‫Let's create a multiplier variable,
‫again a ternary operator here,
‫so if it's miles then what should our multiplier be?
‫Well, let's actually very simply
‫Google what one meter is in miles.
‫One meter to miles, and Google usually gives us
‫a pretty nice response, and so indeed, that it is.
‫So if this is one meter, then all we need to do
‫is to really multiply our result in meters
‫with this number.
‫So let's copy it here, and go back,
‫and so this should be our multiplier
‫in case the unit is meters, or actually in case it's miles.
‫And in case it's meters, well then
‫it's that 0.001 that we used before.
‫We don't want it in meters,
‫because that's not really a readable unit.
‫Instead we want it in kilometers.
‫So now we can go ahead and use out multiplier variable here,
‫give it a save, and let's try it out.
‫So take a look at what we have here in kilometers,
‫so from the previous result, which is 64.
‫That should approximately be 40 miles, so let's send that,
‫and that was pretty close.
‫So 40.2 miles indeed.
‫And so that's our closest tours,
‫and the most farthest away is the City Wonderer,
‫which I think starts in New York or something,
‫and so that is more than 2400 miles away from L.A.
‫If we then set it here to kilometers,
‫then it should be back to getting the value
‫that we had before.
‫Let's put it back to miles
‫because I know that most people watching this course
‫are from the U.S., and so over there they use miles
‫instead of kilometers.
‫So let's save this here as well to our collection
‫get distances to tours from point.
‫So that's it, that wraps up this lecture,
‫and that's all I had to show you about geospatial data.
‫So this video and the last one should have given you
‫a very great overview of how to work
‫with geospatial data in MongoDB.
‫And as I said before there's a ton of possibilities
‫of stuff that you can do in your own applications
‫using this kind of data.