我正在开发一个处理地方的 API。我有一个已构建为自引用并包含一parent_id
列的表。到目前为止,该表中有 144 条记录。
我们的客户端应用程序需要接收嵌套位置。由于我使用的是 Rails,所以我一开始尝试使用序列化程序的强大功能来为我做这件事:
class LocalitySerializer < ActiveModel::Serializer
attributes :id, :name, :postcode, :kind, :latitude, :longitude, :parent_id
has_many :childrens
end
虽然它确实有效,但它似乎并不高效。首先,日志显示对数据库的大量 SQL 查询。当然,我尝试过使用类似的方法来急切加载数据,Locality.includes(:childrens).all
但它不起作用并且没有效果(也许我做错了什么?)
我最终编写了一个递归函数,它获取位置的完整列表 ( Locality.all
) 并检查每个元素的 parent_id 以嵌套它们。所以我删除了LocalitySerializer中的关联:
class LocalitySerializer < ActiveModel::Serializer
attributes :id, :name, :postcode, :kind, :latitude, :longitude, :parent_id
end
并在它自己的序列化程序中单独构建它:
class DictionarySerializer < ActiveModel::Serializer
def attributes
hash = super
hash[:localities] = localities
hash
end
private
def localities
Rails.cache.fetch('localities.json', expires_in: 7.days) do
localities = ActiveModel::ArraySerializer.new(Locality.all, each_serializer: LocalitySerializer).as_json
build_hierarchy(localities, [], nil)
end
end
def build_hierarchy(source, target_array, n)
source.select { |h| h[:parent_id] == n }.each do |h|
h.except!(:parent_id)
target_array << h.clone.merge(childrens: build_hierarchy(source, [], h[:id]))
end
target_array
end
end
虽然这有点快,但恕我直言,它仍然很慢。请注意,我在这里设置了一个低级缓存,以使其在后续请求时更快。我实际上没有做任何基准测试(只是将我的话作为最终用户的看法),但如果它可以帮助任何人找出更快的生成方法,我会很乐意这样做。