0

I am calling some third party API to get locations

https://localhost:3000/api/v1/locations 

this is returning result in json like

[{"location_id": 1,"name": "location1" ,"lat": "22.21","long": "-72.54"},{"location_id": 2,"name": "location2","lat": "45.21","long": "-74.21"}]

With Active Record we can apply distance filter using Geocoder

Location.near([lat, long], 100,units: :km)

But API response is json object ,How can I apply distance filter on json object using Geocoder.

3
  • is Location a model where you are storing the api location data? or just a route you created to fetch it? Commented Jun 22, 2020 at 13:18
  • There is no model, its just a route to fetch data from the API, Commented Jun 22, 2020 at 13:49
  • I don't have any model or something, just have the API route to fetch the locations from API Commented Jun 22, 2020 at 13:50

1 Answer 1

2

Unfortunately geocoder does only support ActiveRecord and MongoDB as storage backends but not JSON. With ActiveRecord / Mongo geocoder can also leverage the query language of the database (e.g. SQL) to efficiently find locations near a point. In your case you have now basically two options:

Store JSON data in ActiveRecord

You could store your JSON data in a database and use ActiveRecord to query the data. There is already a good documentation for this on the gem official GitHub page here https://github.com/alexreisner/geocoder#geospatial-database-queries.

Create ActiveRecord like object

If you don't need to store the data from your API request I would recommend to use an Active Record like volatile data storage.

class Location
  attr_reader :id, :name, :lat, :long

  def initialize(id:, name:, lat:, long:)
    @id = id
    @name = name
    @lat = lat
    @long = long
  end

  def to_coordinates
    [lat.to_f, long.to_f]
  end

  class << self
    attr_accessor :locations

    def from_json(json)
      json.each do |location|
        locations << new(
          id: location[:location_id],
          name: location[:name],
          lat: location[:lat],
          long: location[:long]
        )
      end
    end

    def all
      locations
    end
  end

  self.locations = []
end

json = [
  {"location_id": 1, "name": "location1", "lat": "22.21", "long": "-72.54" },
  {"location_id": 2, "name": "location2", "lat": "45.21", "long": "-74.21" }
]

Location.from_json(json)
puts Location.all

We now 'import' your API JSON response and store it in an array as a class attribute in Location. This also has the advantage that you work with objects and not with hashes / JSON anymore.

Now we can create a near class method to select all locations close to one point.

def near(lat, long, radius: 20, units: :km)
  all.select do |location|
    Geocoder::Calculations.distance_between(location, [lat, long], units: units) < radius
  end
end

The disadvantage here is that we need to iterate over all locations and calculate the distance as we don't have a query language for the JSON data. If performance is an issue, I would suggest to use an SQL database (see previous suggestion).

Full example

require "geocoder"

class Location
  attr_reader :id, :name, :lat, :long

  def initialize(id:, name:, lat:, long:)
    @id = id
    @name = name
    @lat = lat
    @long = long
  end

  def to_coordinates
    [lat.to_f, long.to_f]
  end

  class << self
    attr_accessor :locations

    def from_json(json)
      json.each do |location|
        locations << new(
          id: location[:location_id],
          name: location[:name],
          lat: location[:lat],
          long: location[:long]
        )
      end
    end

    def all
      locations
    end

    def near(lat, long, radius: 20, units: :km)
      all.select do |location|
        Geocoder::Calculations.distance_between(location, [lat, long], units: units) < radius
      end
    end
  end

  self.locations = []
end

json = [
  {"location_id": 1, "name": "location1", "lat": "22.21", "long": "-72.54" },
  {"location_id": 2, "name": "location2", "lat": "45.21", "long": "-74.21" }
]

Location.from_json(json)

puts Location.near(45.21, -74.21)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.