<aside> 💡

→ Link zum Airtable Template: https://www.airtable.com/universe/expcw5Bfdsa7eE6XC/postleitzahl-distanz-sortierung

</aside>

Die folgenden Code-Snippets kannst du in die jeweiligen Airtable Scripting-Blocks einfügen und die Airtable erfüllt direkt ihren Zweck.

Wahrscheinlich willst du die Airtable jedoch an deinen Anwendungsfall anpassen. Das ist super, wenn du jedoch Namen von Tabellen und Feldern veränderst musst du diese auch im Code anpassen, damit er weiterhin funktioniert. Solche Namen sind im Code grün.

Code:

Eintrag mit Längen und Breitengrad versehen:

let table = base.getTable("Einträge sortiert nach Distanz zu Such-PLZ");
let query = await table.selectRecordsAsync();

async function getCoordinates(plz) {
    let url = `https://nominatim.openstreetmap.org/search?postalcode=${plz}&country=Germany&format=json`;
    let response = await fetch(url, {
        headers: { "User-Agent": "AirtablePLZTool/1.0 ([email protected])" }
    });
    let data = await response.json();
    if (data.length > 0) {
        return {
            lat: parseFloat(data[0].lat),
            lon: parseFloat(data[0].lon)
        };
    } else {
        return null;
    }
}

// Schleife durch alle Einträge
for (let record of query.records) {
    let plz = record.getCellValue("Postleitzahl");
    let latitude = record.getCellValue("Breitengrad");
    let longitude = record.getCellValue("Längengrad");

    // Prüfen, ob Latitude und Longitude noch nicht eingetragen sind
    if (plz && (latitude === null || longitude === null)) {
        let coords = await getCoordinates(plz);
        if (coords) {
            await table.updateRecordAsync(record.id, {
                "Breitengrad": coords.lat,
                "Längengrad": coords.lon
            });
        } else {
            console.log(`Koordinaten nicht gefunden für PLZ: ${plz}`);
        }
    }
}

Koordinaten der Such-PLZ ermitteln:

let table = base.getTable("Such-PLZ");
let query = await table.selectRecordsAsync();

async function getCoordinates(plz) {
    try {
        let url = `https://nominatim.openstreetmap.org/search?postalcode=${plz}&country=Germany&format=json`;
        let response = await fetch(url, {
            headers: { "User-Agent": "AirtablePLZTool/1.0 ([email protected])" }
        });
        if (!response.ok) throw new Error(`HTTP error: ${response.status}`);
        let data = await response.json();
        if (data.length > 0) {
            return {
                lat: parseFloat(data[0].lat),
                lon: parseFloat(data[0].lon)
            };
        } else {
            return null;
        }
    } catch (error) {
        console.error(`Error fetching coordinates for PLZ ${plz}:`, error);
        return null;
    }
}

let updates = [];
for (let record of query.records) {
    let plz = record.getCellValue("Such PLZ");

    // Nur für Datensätze mit einer PLZ
    if (plz) {
        let coords = await getCoordinates(plz);
        if (coords) {
            updates.push({
                id: record.id,
                fields: {
                    "Breitengrad": coords.lat,
                    "Längengrad": coords.lon
                }
            });
        } else {
            console.log(`Koordinaten nicht gefunden für PLZ: ${plz}`);
        }
        // Füge eine Verzögerung hinzu, um die Rate-Limits zu respektieren
        await new Promise(resolve => setTimeout(resolve, 1000));
    }
}

// Batch-Updates
while (updates.length > 0) {
    await table.updateRecordsAsync(updates.slice(0, 50));
    updates = updates.slice(50);
}

Distanzen berechnen:

let suppliersTable = base.getTable("Einträge sortiert nach Distanz zu Such-PLZ");
let suppliersQuery = await suppliersTable.selectRecordsAsync();

let userTable = base.getTable("Such-PLZ");
let userQuery = await userTable.selectRecordsAsync();
let userRecord = userQuery.records[0]; // Annahme: Nur eine Zeile

let userLat = userRecord.getCellValue("Breitengrad");
let userLon = userRecord.getCellValue("Längengrad");

function haversine(lat1, lon1, lat2, lon2) {
    const R = 6371; // Erdradius in km
    const toRad = (x) => (x * Math.PI) / 180;
    let dLat = toRad(lat2 - lat1);
    let dLon = toRad(lon2 - lon1);
    let a =
        Math.sin(dLat / 2) * Math.sin(dLat / 2) +
        Math.cos(toRad(lat1)) *
            Math.cos(toRad(lat2)) *
            Math.sin(dLon / 2) *
            Math.sin(dLon / 2);
    let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    return R * c;
}

for (let supplierRecord of suppliersQuery.records) {
    let supplierLat = supplierRecord.getCellValue("Breitengrad");
    let supplierLon = supplierRecord.getCellValue("Längengrad");

    if (supplierLat && supplierLon) {
        let distance = haversine(userLat, userLon, supplierLat, supplierLon);
        await suppliersTable.updateRecordAsync(supplierRecord.id, {
            "Distanz zu Such-PLZ (km)": parseFloat(distance.toFixed(2)) // Als Zahl speichern
        });
    }
}