egypt-geo-navigator
v1.0.0
Published
Bilingual (Arabic/English) administrative address library of Egypt (Governorates, Districts/Markaz, Villages/Neighborhoods) for Node.js, React, and MongoDB.
Maintainers
Readme
Egypt Geo Navigator
A lightweight, bilingual (Arabic & English) administrative address database and API for Egypt (Governorates ➔ Districts/Markaz/Qism ➔ Villages/Neighborhoods). Built with Node.js, React, MongoDB, and TypeScript.
Features:
- 100% complete coverage: Includes all 27 Governorates, 173 Districts, and 12,067 Villages & Neighborhoods.
- Bilingual names: Every record has correct Arabic (
nameAr) and English (nameEn) names, using advanced phonetic transliteration for records missing Arabic data in GeoNames. - Geospatial coordinates: Includes
latitudeandlongitudecoordinates for districts and locations. - Nearest-neighbor mapping: Every village is automatically mapped to its closest administrative district center.
- Ready for MongoDB: Generates a flat JSON array structured for direct MongoDB import.
- Bilingual Autocomplete Search: In-memory prefix search for dropdown inputs in React.
- Geolocation support: Query closest locations by latitude and longitude.
📦 Project Structure
data/egypt-hierarchy.json: Hierarchical structure (Governorates ➔ Districts ➔ Locations) perfect for cascading dropdowns in React.egypt-locations-mongo.json: Flat JSON array ready to be imported into MongoDB.
src/consts.py: Curated governorate name constants.transliterate.py: Phonetic Romanized-to-Arabic place name transliterator.parser.py: Python processing engine that parses GeoNamesEG.txtand exports database files.
dist/: Compiled TypeScript library.index.ts: TypeScript library interface and query functions.tests/: Automated Python and Node integration test suites.
💾 MongoDB Integration
You can easily load the data into your MongoDB database.
1. Import with mongoimport
Run the following command in your terminal to import the flat JSON array directly into a MongoDB collection (e.g. locations in database erp):
mongoimport --db erp --collection locations --file data/egypt-locations-mongo.json --jsonArray --drop2. Mongoose Schema Definition (TypeScript)
Define your schema and TypeScript interfaces in your Node.js backend:
import { Schema, model, Document } from 'mongoose';
export interface IEgyptLocation extends Document {
_id: string; // E.g., "gov_09", "dist_345955", "loc_346077"
name: {
ar: string;
en: string;
};
type: 'governorate' | 'district' | 'village' | 'neighborhood';
coordinates?: {
lat: number;
lng: number;
};
parentId?: string; // Links to parent _id
hierarchy: {
governorate: {
id: string;
nameAr: string;
nameEn: string;
};
district?: {
id: string;
nameAr: string;
nameEn: string;
};
};
}
const EgyptLocationSchema = new Schema<IEgyptLocation>({
_id: { type: String, required: true },
name: {
ar: { type: String, required: true },
en: { type: String, required: true }
},
type: { type: String, enum: ['governorate', 'district', 'village', 'neighborhood'], required: true },
coordinates: {
lat: { type: Number },
lng: { type: Number }
},
parentId: { type: String },
hierarchy: {
governorate: {
id: { type: String, required: true },
nameAr: { type: String, required: true },
nameEn: { type: String, required: true }
},
district: {
id: { type: String },
nameAr: { type: String },
nameEn: { type: String }
}
}
});
// Create text index for bilingual search in MongoDB
EgyptLocationSchema.index({ 'name.ar': 'text', 'name.en': 'text' });
export const EgyptLocation = model<IEgyptLocation>('Location', EgyptLocationSchema);⚡ React & Node.js Library API (Highly Optimized)
The package provides TypeScript query functions. Statically imported metadata is synchronous, while larger datasets are asynchronously lazyloaded on-demand to keep your frontend bundle footprint extremely small (less than 20KB!).
Import the library
import {
getGovernorates,
getDistricts,
getLocations,
search,
getNearestLocations
} from 'egypt-geo-navigator';1. Cascading Dropdowns in React (Code-Split)
// 1. Load all governorates for the first select field (Synchronous: ~1.5KB)
const governorates = getGovernorates();
// Output: [{ id: "09", nameAr: "المنوفية", nameEn: "Monufia" }, ...]
// 2. Load districts when a governorate is selected (Synchronous: ~1KB)
const districts = getDistricts("09");
// Output: [{ id: "345955", nameAr: "الباجور", nameEn: "Al Bajur", coordinates: { lat: 30.42, lng: 31.05 } }, ...]
// 3. Load villages when a district is selected (Asynchronous: dynamically loads gov-09.json chunk ~100KB)
const villages = await getLocations("09", "345955");
// Output: [{ id: "346077", nameAr: "زاوية جروان", nameEn: "Zawiyat Jarwan", type: "village", coordinates: { lat: 30.44, lng: 31.03 } }, ...]2. Autocomplete Bilingual Search (Asynchronous)
Instantly search across all governorates, districts, and villages. Lazy-loads the full hierarchy on-demand:
const results = await search("دمنهور");
// Or search in English:
const resultsEn = await search("tanta");3. Geolocation & Shipping Distance (Asynchronous)
Find the nearest villages or branches to a customer's location. Lazy-loads the full hierarchy on-demand:
// Query closest locations to coordinates (lat, lng)
const nearest = await getNearestLocations(29.9792, 31.1342, 3);
// Output:
// [
// { id: "346002", nameAr: "نزلة السمان", nameEn: "Nazlat As Samman", distanceKm: 0.47, ... },
// ...
// ]🧪 Testing
Run Python tests:
python -m unittest tests/test_parser.pyRun Node integration tests:
node tests/test_library.js🤝 Contributing
We welcome contributions from the community! If you find any misspelled place name (Arabic or English), formatting error, or missing location:
- Open an Issue: Report the incorrect place name with its correct spelling.
- Submit a Pull Request (PR): Feel free to submit a PR correcting the spelling in the source files.
For major features or database updates, please open an issue first to discuss your proposed changes.
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
