From 54fcf2078e17c7aef8c76ae671a86be506ca2105 Mon Sep 17 00:00:00 2001 From: Chris Hallberg Date: Fri, 3 Feb 2023 12:45:01 -0500 Subject: [PATCH] feat(update): add update script. --- .gitignore | 6 ++++++ README.md | 16 ++++++++++++---- package.json | 29 ++++++++++++++-------------- update.js | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 18 deletions(-) create mode 100644 update.js diff --git a/.gitignore b/.gitignore index 5148e52..a2a7856 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ +# GeoNames data +US.txt +readme.txt +allCountries.txt +allCountries.zip + # Logs logs *.log diff --git a/README.md b/README.md index b6bb174..0a7a51d 100644 --- a/README.md +++ b/README.md @@ -26,10 +26,18 @@ Returns the closest place object to the specified coordinates. ### Why? -I saw a lot of zip database modules on npm, but I was displeased with three aspects +I saw a lot of zip database modules on npm, but I was displeased with three aspects: -* Old data (zips uses 2010 US Census data from [geonames.org](http://www.geonames.org/), the most up-to-date I could find). -* Huge, raw data (zips' data is pre-processed so it can just load and go). -* List searching (zips organizes its data into trees instead of going down a list until a match is found or a large hash table). +- Old data (zips uses US Postcode data from [geonames.org](http://www.geonames.org/), the most up-to-date I could find). +- Huge, raw data (zips' data is pre-processed so it can just load and go). +- List searching (zips organizes its data into trees instead of going down a list until a match is found or a large hash table). I hope you're happy too. + +### Update + +1. Download `US.zip` from [GeoNames Postcodes Download Server](https://download.geonames.org/export/zip/) +1. Extract `US.txt` to root. +1. `npm run update`. + +*Last update: 2023-02-03* diff --git a/package.json b/package.json index 4d85f7e..186648c 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,25 @@ { "name": "zips", - "version": "1.1.2", + "version": "1.1.2.2023-02-03", "description": "Light, fast, tree-based way to get cities by zipcode and location.", - "main": "index.js", - "scripts": { - "test": "mocha" + "author": "Chris Hallberg", + "homepage": "https://github.com/crhallberg/zips#readme", + "license": "MIT", + "bugs": { + "url": "https://github.com/crhallberg/zips/issues" }, "repository": { "type": "git", "url": "https://github.com/crhallberg/zips.git" }, + "main": "index.js", + "scripts": { + "update": "node ./update.js", + "test": "mocha" + }, + "devDependencies": { + "mocha": "^3.5.3" + }, "keywords": [ "zipcodes", "zip", @@ -18,14 +28,5 @@ "zipcode", "postal", "code" - ], - "author": "Chris Hallberg", - "license": "MIT", - "bugs": { - "url": "https://github.com/crhallberg/zips/issues" - }, - "homepage": "https://github.com/crhallberg/zips#readme", - "dev-dependencies": { - "mocha": "^3.2.0" - } + ] } diff --git a/update.js b/update.js new file mode 100644 index 0000000..323fa1e --- /dev/null +++ b/update.js @@ -0,0 +1,54 @@ +const fs = require('node:fs'); +const readline = require('node:readline'); + +function parseRow(rowStr) { + const parts = rowStr.split("\t").map((str) => str.trim()); + return { + country: parts[0], + zip: parts[1], + city: parts[2], + state: parts[4], + lat: parseFloat(parts[9]), + long: parseFloat(parts[10]), + }; +} + +const locTree = { + index: [], + zones: {}, +}; + +const rl = readline.createInterface({ input: fs.createReadStream("./US.txt") }); + +rl.on("line", (line) => { + const place = parseRow(line); + + const index = locTree.index.length; + locTree.index.push(place); + + function addIndex(latIndex, longIndex, index) { + if (typeof locTree.zones[latIndex] == "undefined") { + locTree.zones[latIndex] = {}; + } + + if (typeof locTree.zones[latIndex][longIndex] == "undefined") { + locTree.zones[latIndex][longIndex] = []; + } + + locTree.zones[latIndex][longIndex].push(index); + } + + let latIndex = Math.floor(Math.abs(parseFloat(place.lat, 10))); + let longIndex = Math.floor(Math.abs(parseFloat(place.long, 10))); + addIndex(latIndex, longIndex, index); + + latIndex = Math.ceil(Math.abs(parseFloat(place.lat, 10))); + longIndex = Math.ceil(Math.abs(parseFloat(place.long, 10))); + addIndex(latIndex, longIndex, index); +}); + +rl.on("close", () => { + fs.writeFileSync("data/loc-tree.json", JSON.stringify(locTree), "UTF8"); + + console.log("DONE"); +});