Created
March 19, 2024 19:39
-
-
Save steinbring/90870669f8887245ef4ddf089f63297c to your computer and use it in GitHub Desktop.
A CLI node script for syncing https://github.com/dr5hn/countries-states-cities-database/blob/master/countries%2Bstates%2Bcities.json to a Firebase Cloud Firestore
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const admin = require('firebase-admin'); | |
const fs = require('fs'); | |
const { geohashForLocation } = require('geofire-common'); | |
// Initialize Firebase Admin | |
const serviceAccount = require('./firebase-adminsdk.json'); | |
admin.initializeApp({ | |
credential: admin.credential.cert(serviceAccount) | |
}); | |
const db = admin.firestore(); | |
// Helper functions | |
const generateSlug = (...parts) => parts.map(part => part.toLowerCase().replace(/[\s\W-]+/g, '-')).join('-'); | |
const sleep = (milliseconds) => new Promise(resolve => setTimeout(resolve, milliseconds)); | |
const lastProcessedSlugFile = './lastProcessedSlug.txt'; | |
const saveLastProcessedSlug = (slug) => { | |
fs.writeFileSync(lastProcessedSlugFile, slug); | |
}; | |
const readLastProcessedSlug = () => { | |
try { | |
return fs.readFileSync(lastProcessedSlugFile, 'utf8'); | |
} catch (e) { | |
return null; // If file doesn't exist, start from the beginning | |
} | |
}; | |
// Populate Firestore with geohash | |
const populateFirestore = async (data) => { | |
const lastProcessedSlug = readLastProcessedSlug(); | |
let hasReachedLastProcessed = lastProcessedSlug === null; | |
for (const country of data) { | |
const countrySlug = generateSlug(country.region, country.subregion, country.name); | |
for (const state of country.states) { | |
const stateSlug = generateSlug(countrySlug, state.name); | |
for (const city of state.cities) { | |
const citySlug = generateSlug(stateSlug, city.name); | |
if (!hasReachedLastProcessed && citySlug === lastProcessedSlug) { | |
hasReachedLastProcessed = true; | |
} else if (!hasReachedLastProcessed) { | |
continue; // Skip until we reach the last processed | |
} | |
// Calculate geohash | |
const geohash = geohashForLocation([parseFloat(city.latitude), parseFloat(city.longitude)]); | |
const docRef = db.collection('locations').doc(citySlug); | |
await docRef.set({ | |
region: country.region, | |
subregion: country.subregion, | |
country: country.name, | |
state: state.name, | |
city: city.name, | |
latitude: city.latitude, | |
longitude: city.longitude, | |
slug: citySlug, | |
geohash // Include geohash in document | |
}); | |
console.log(`Added: ${citySlug}`); | |
saveLastProcessedSlug(citySlug); // Save this slug as the last processed | |
await sleep(500); // Wait to prevent hitting rate limits | |
} | |
} | |
} | |
}; | |
// Main function to read JSON and populate Firestore | |
const main = async () => { | |
const data = JSON.parse(fs.readFileSync('./countries+states+cities.json', 'utf8')); | |
await populateFirestore(data); | |
console.log('Data population completed.'); | |
}; | |
main().catch(console.error); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment