From ee10c90a4f3aaf99c84ad532b4737748d6481d34 Mon Sep 17 00:00:00 2001 From: jspeis Date: Thu, 8 Mar 2018 13:50:24 -0500 Subject: [PATCH] adds dynamic column name selection and groups results by geographic level --- src/api/index.js | 52 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/src/api/index.js b/src/api/index.js index 5fd372b..2c9703a 100755 --- a/src/api/index.js +++ b/src/api/index.js @@ -1,9 +1,11 @@ import {Router} from "express"; -import levels from "config/levels.json"; import {version} from "package"; import dbgeo from "dbgeo"; +const levels = require("config/acs_levels.json"); + + function topofy(data, httpResult) { const precision = 5; const quantization = 100000; @@ -23,13 +25,30 @@ const levelLookup = geoId => { "140": "tract", "050": "county", "040": "state", + "310": "msa", "160": "place", "860": "zip", + "795": "puma", "970": "school-district" }; return levelMap[prefix]; }; + +const groupByLevel = dataArr => { + const result = {}; + dataArr.forEach(row => { + const geoId = row.geoid; + const myPrefix = geoId.slice(0, 3); + const lvl = levelLookup(myPrefix); + if (!Object.keys(result).includes(lvl)) { + result[lvl] = []; + } + result[lvl].push(row); + }); + return result; +} + export default ({db}) => { const api = new Router(); @@ -48,8 +67,8 @@ export default ({db}) => { } const targetTable = `${levels[level].schema}.${levels[level].table}`; - - const qry = `SELECT * from ${targetTable} s1, + const cols = levels[level].columns.map(x => `s2."${x}"`).join(",") || "*"; + const qry = `SELECT ${cols} from ${targetTable} s1, ${targetTable} s2 WHERE ST_Touches(s1.geom, s2.geom) AND s1.geoid = $1;`; @@ -131,29 +150,32 @@ export default ({db}) => { }); }); - api.get("/related", (req, httpResult) => { - const geoId = req.query.target; - // const gisCmd = req.params.op === "within" ? "ST_Within" : "ST_Intersects"; + api.get("/related/:geoId", (req, httpResult) => { + const geoId = req.params.geoId || req.query.target; const level1 = levelLookup(geoId); const includeGeom = req.query.includeGeom ? ", s2.geom" : ""; - const targetTable1 = `${levels[level1].schema}.${levels[level1].table}`; const targetId1 = levels[level1].id; + const queries = []; Object.keys(levels).forEach(level => { - const targetTable2 = `${levels[level].schema}.${levels[level].table}`; - - const qry = `SELECT s2.geoid, s2.name ${includeGeom} from ${targetTable1} s1, - ${targetTable2} s2 - WHERE (ST_Area(st_intersection(s2.geom, s1.geom)) / st_area(s1.geom)) > 0.001 - AND s1.${targetId1} = $1`; - queries.push(qry); + if (level !== level1) { + const targetTable2 = `${levels[level].schema}.${levels[level].table}`; + const nameColumn2 = levels[level].nameColumn || "name"; + const gidColumn2 = levels[level].geoColumn || "geoid"; + const qry = `SELECT s2."${gidColumn2}", s2."${nameColumn2}" as name ${includeGeom} from ${targetTable1} s1, + ${targetTable2} s2 + WHERE ST_Intersects(s2.geom, s1.geom) + AND s1.${targetId1} = $1`; + queries.push(qry); + } }); Promise.all(queries.map(q => db.query(q, geoId))) .then(values => values.reduce((acc, x) => [...acc, ...x], [])) - .then(results => topofy(results, httpResult)) + .then(groupByLevel) + .then(results => httpResult.json(results)) .catch(error => { console.error("An error occured", error); httpResult.json({error});