Database API

Tutorial: browse, look up, traverse hierarchy, fuzzy search, validate, and export Philippine PSGC data (42,010 barangays) using the typed barangay Database API.
Author

bendlikeabamboo

A quick walkthrough of the barangay Database API for browsing, searching, validating, and exporting Philippine geographic data.

Installation

See Get Started — Installation. Quick one-liner:

pip install barangay

1. Browse Administrative Levels

Pre-built views give you direct access to every admin level in the PSGC database:

from barangay import regions, provinces, municipalities, cities, barangays

print(regions)     # <PSGC region database: 18 records>
print(provinces)   # <PSGC province database: 82 records>
print(barangays)   # <PSGC barangay database: 42010 records>

Each view supports iteration, containment checks, and counting:

print(len(barangays))          # 42010
print("1907005010" in barangays)  # True

for region in regions:
    print(region.name)
# Bangsamoro Autonomous Region In Muslim Mindanao (BARMM)
# Cordillera Administrative Region (CAR)
# MIMAROPA Region
# ...

2. Look Up a Record

Look up a single record by name or PSGC ID:

# By name
brgy = barangays.get(name="Tongmageng")
print(brgy)  # <barangay: Tongmageng (1907005010)>

# By PSGC ID (always unique)
brgy = barangays.lookup("1907005010")
print(brgy.name)  # Tongmageng

If a name matches multiple records, get() raises MultipleResultsError. Use lookup() with a PSGC ID for guaranteed-unique lookups. See Handling Errors for full details.

3. Traverse the Hierarchy

Each record knows its position in the administrative hierarchy:

brgy = barangays.get(name="Tongmageng")

print(brgy.region)       # Bangsamoro Autonomous Region In Muslim Mindanao (BARMM)
print(brgy.province)     # Tawi-Tawi
print(brgy.municipality)  # Sitangkai
1print(brgy.parent)       # <municipality: Sitangkai (1907005000)>

2for ancestor in brgy.ancestors:
    print(repr(ancestor))
# <municipality: Sitangkai (1907005000)>
# <province: Tawi-Tawi (1907000000)>
# <region: Bangsamoro Autonomous Region In Muslim Mindanao (BARMM) (1900000000)>
1
.parent returns the direct parent record (here, the municipality). The resolved-name properties (.region, .province, .municipality) are shortcuts derived from the same hierarchy walk.
2
.ancestors walks all the way to the root, from nearest parent outward.

Navigate downward with .children:

manila = cities.get(name="City of Manila")
for child in manila.children[:3]:
    print(repr(child))
# <submunicipality: Tondo I/II (1380601000)>
# <submunicipality: Binondo (1380602000)>
# <submunicipality: Quiapo (1380603000)>
TipPSGC IDs are globally unique

Prefer .get(psgc_id=...) / .lookup(psgc_id) over name-based lookups when you have a code. Names like “San Jose” match hundreds of records; a PSGC ID always resolves to exactly one.

4. Export to Pandas

Export any view directly to a DataFrame or list of dicts:

df = barangays.to_frame()
print(df.columns.tolist())
# ['name', 'type', 'psgc_id', 'parent_psgc_id', 'nicknames', 'extensions',
#  'region', 'province', 'highly_urbanized_city', 'independent_component_city',
#  'component_city', 'municipality', 'submunicipality',
#  'special_geographic_area', 'barangay']
print(df.shape)  # (42010, 15)

data = barangays.to_dicts()
print(len(data))  # 42010
print(data[0])
# {'name': 'Arco', 'type': 'barangay', 'psgc_id': '1900702001', ...}

Each record includes six base fields (name, type, psgc_id, parent_psgc_id, nicknames, extensions) plus nine resolved hierarchy fields (region, province, highly_urbanized_city, independent_component_city, component_city, municipality, submunicipality, special_geographic_area, barangay) for immediate use in analysis. See the Database reference for the full column list.

6. Validate Addresses

Validate addresses against the PSGC masterlist with a high-confidence threshold:

from barangay import validate, validate_many

v = validate("Tongmageng, Sitangkai, Tawi-Tawi")
print(v.valid, v.matched_name, v.score)  # True Tongmageng 100.0

Validate multiple addresses at once:

results = validate_many([
    "Tongmageng, Sitangkai, Tawi-Tawi",
    "Brgy 291, City of Manila",
    "Nonexistent Place",
])
for r in results:
    status = "valid" if r.valid else "invalid"
    print(f"{r.input!r} -> {status}")
# 'Tongmageng, Sitangkai, Tawi-Tawi' -> valid
# 'Brgy 291, City of Manila' -> invalid
# 'Nonexistent Place' -> invalid

The default threshold is 95.0. Lower it for more lenient matching:

v = validate("Brgy 291, City of Manila", threshold=80.0)
print(v.valid, v.score)  # False None

7. Handling Errors

RecordNotFoundError — No match found

.get() raises RecordNotFoundError when no record matches your query:

from barangay import barangays, RecordNotFoundError

try:
    brgy = barangays.get(name="DoesNotExist")
except RecordNotFoundError as e:
    print(e)
    # No barangay with name 'DoesNotExist'.
    # See https://.../learn/database-api.html#handling-errors

MultipleResultsError — Multiple matches found

Some names like “San Jose” or “San Roque” appear hundreds of times across the Philippines. .get(name=...) raises MultipleResultsError when more than one record matches:

from barangay import barangays, MultipleResultsError

try:
    brgy = barangays.get(name="San Jose")
except MultipleResultsError as e:
    print(e)
    # Name 'San Jose' matched 244 records. Use psgc_id for exact lookup, or iterate.
    # See https://.../learn/database-api.html#handling-errors

How to resolve: Use a PSGC ID

PSGC IDs are globally unique. Use .get(psgc_id=...) for exact lookups:

brgy = barangays.get(psgc_id="1380100001")
print(brgy)  # <barangay: Barangay 1 (1380100001)>

How to resolve: Iterate and filter

When you don’t have a PSGC ID, iterate the view and filter by additional criteria:

# Get all barangays named "San Jose"
matches = [rec for rec in barangays if rec.name == "San Jose"]
print(len(matches))  # 244

# Narrow down by parent city (City of Manila is a highly urbanized city,
# so filter on highly_urbanized_city instead of municipality)
san_jose_in_qc = [
    rec for rec in barangays
    if rec.name == "San Jose" and rec.highly_urbanized_city == "Quezon City"
]
for rec in san_jose_in_qc:
    print(rec)  # <barangay: San Jose (1381300100)>

# Narrow down by region
san_jose_in_cavite = [
    rec for rec in barangays
    if rec.name == "San Jose" and rec.province == "Cavite"
]
for rec in san_jose_in_cavite:
    print(f"{rec.name}{rec.municipality}, {rec.province}")

How to resolve: Use lookup() for nullable lookups

If you want None instead of an exception, use .lookup():

rec = barangays.lookup("9999999999")  # returns None instead of raising
if rec is not None:
    print(rec.name)
else:
    print("Not found")

Next Steps