Search code examples
javascriptmeteorgeolocation

MeteorJS: Display Posts with locations within x miles of current location


I am working on an application that will display the posts of people within a certain amount of distance of their location.

Whenever a post is created a value of location is created which is stored with: {"lat":39.7230949,"lng":-104.83521619999999}. The lat and longitude of the current location when the post was made.

This is from a function, Geolocation.latLng();, which prints out the object with the lat and lng of the current device.

I am now trying to figure out how to have the page which lists all the post, only show post that fall within a radius of the devices current location.

Here is my current function which lists all the post from my database.

Template.yakResults.searchResults = function () {
    var keyword  = Session.get("search-query");
    var query = new RegExp( keyword, 'i' );
    var results = Yaks.find( { $or: [{'yak': query}] }, {sort: {score: -1}});
    return {results: results};
}

What do I have to do to get the results to be with say 10 mile radius of the devices current long/lat which can be found with the function mentioned above.

I imagine I use an if statement of some sort or maybe a filer when I am finding the posts in the Yaks collection?

Does any one have any idea on how I can filter the collection of posts to do something similar to this?

If i need to post up more code to make it easier to understand my question please let me know and I will.


Solution

  • Figured it out. For any one who may be trying to do something similar in the future, here is what I did.

    First I had have the posts location formatted to geoJSON before it could go into the database. Here is the code I used in order to achieve this.(NOTE: Gelocation.latLng(); function is from this meteor plugin(https://atmospherejs.com/mdg/geolocation)).

    This is the code called whenever the yak is submitted.

    Template.yaksSubmit.events({
    'submit .yaksSubmitForm': function(event) {
    
            event.preventDefault();
            var yak = event.target.yak.value; //get yak input value
            var yakLocation = Geolocation.latLng(); // location of yak
    
            var lat = yakLocation.lat;
    
            var lng = yakLocation.lng;
    
            //check if the value is empty
            if(yak == "") {
                alert("You can't inert a empty yak!");
            } else {
                Meteor.call('yakInsert', yak, lng, lat);
                Router.go('yaksList');
            }
        }
    });
    

    Here is the yakInster method being called from my server.js file.

    yakInsert: function(yak, lng, lat) {
        var postId = Yaks.insert({
            yak: yak,
            loc : {
                type: "Point",
                coordinates: [ lng, lat ]
            },
            score: 0,
            submitted: new Date(),
            user: Meteor.userId(),
            lng: lng,
            lat: lat
            // Geolocation.latLng(); JSON.stringify(yakLocation)
        });
    }
    

    Then I stored the devices long/lat in into a Session with a helper.

    Template.yakResults.helpers({
    lat: function() {
            var currentLocation = Geolocation.latLng(); // location of yak
            var lat = currentLocation.lat;
            Session.set("device-lat", lat);
        },
        lng: function() {
            var currentLocation = Geolocation.latLng(); // location of yak
            var lng = currentLocation.lng;
            Session.set("device-lng", lng);
        }
    });
    

    And then for my function to display all my posts I used the information explained in this blogpost on mongolab(http://blog.mongolab.com/2014/08/a-primer-on-geospatial-data-and-mongodb/). Here is what the function looks like

    Template.yakResults.searchResults = function () {
        var lng = Session.get("device-lng");
        var lat = Session.get("device-lat");
        var query = new RegExp( keyword, 'i' );
        var results = Yaks.find( {
         loc:
           { $near :
              {
                $geometry:{ type:"Point", coordinates:[ lng, lat]},
                $minDistance: 0,
                $maxDistance: 5000
              }
           }
       });
        return {results: results};
    }
    

    This got the posts to display with their order determined by the location of each yak/post relative to the device's location.

    the $minDistance & $maxDistance are in meters.

    This might not be the best way to make it work but It worked for me. Just thought I would share it incase anybody else could use it.