ruby-on-rails - Rails 中 Json 数组上的地理编码器方法
问题描述
我正在调用一些第三方 API 来获取位置
https://localhost:3000/api/v1/locations
这是在 json 中返回结果,例如
[{"location_id": 1,"name": "location1" ,"lat": "22.21","long": "-72.54"},{"location_id": 2,"name": "location2","lat": "45.21","long": "-74.21"}]
使用 Active Record,我们可以使用 Geocoder 应用距离过滤器
Location.near([lat, long], 100,units: :km)
但是 API 响应是 json 对象,如何使用 Geocoder 对 json 对象应用距离过滤器。
解决方案
不幸的是,geocoder 只支持 ActiveRecord 和 MongoDB 作为存储后端,但不支持 JSON。使用 ActiveRecord / Mongo 地理编码器还可以利用数据库的查询语言(例如 SQL)来有效地查找点附近的位置。在您的情况下,您现在基本上有两种选择:
在 ActiveRecord 中存储 JSON 数据
您可以将 JSON 数据存储在数据库中并使用 ActiveRecord 查询数据。这里的 gem 官方 GitHub 页面上已经有一个很好的文档https://github.com/alexreisner/geocoder#geospatial-database-queries。
创建类似 ActiveRecord 的对象
如果您不需要存储 API 请求中的数据,我建议您使用 Active Record,如易失性数据存储。
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
我们现在“导入”您的 API JSON 响应并将其存储在一个数组中作为 Location 中的类属性。这还具有您使用对象而不是哈希/ JSON 的优点。
现在我们可以创建一个near
类方法来选择靠近一个点的所有位置。
def near(lat, long, radius: 20, units: :km)
all.select do |location|
Geocoder::Calculations.distance_between(location, [lat, long], units: units) < radius
end
end
这里的缺点是我们需要遍历所有位置并计算距离,因为我们没有 JSON 数据的查询语言。如果性能是一个问题,我建议使用 SQL 数据库(请参阅之前的建议)。
完整示例
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)
推荐阅读
- flutter - 我如何调用,不同语言环境的不同字体 - 使用按钮
- html - 为什么下划线在深色模式下不显示?
- javascript - GSAP 时间线中的 Swiper 动画,同时开始
- quartz.net - 具有多个微服务的 Quartz 集群
- python-3.x - 预训练模型中的大文本问题 - t5-large
- dhcp - 发送发现数据包而不释放是否正确?
- flutter - 如何从博世激光测量蓝牙设备接收数据使用颤振
- python - 有没有办法只从 OSM 下载车辆网络作为 .osm 文件?
- c# - 开源Unity拦截,策略注入如何拦截几种类型
- c# - 在 DataTable 速度优化 WPF DataGrid 中查找和编辑行