Große Datenmengen performant aus FileMaker übertragen und anzeigen – ohne Wartezeit

In FileMaker große Datenmengen zu verarbeiten, kann schnell zu Performance-Problemen führen. Besonders wenn FileMaker noch im Hintergrund sortiert oder aggregiert, kann die Benutzeroberfläche einfrieren oder es dauert mehrere Sekunden, bis die Daten sichtbar sind. Das Problem stellt sich immer wieder bei Altlösungen die 10 oder 20 Jahre alt sind. Häufig sind diese Datenbanken bis ins kleinste an die Kunden-Prozesse angepasst. Ein Neubau unrealistisch bis unbezahlbar. Performance-Probleme nur in den langen Listenansichten mit Unmengen an Datensätzen, diese dann noch mit Sortierungen und Formelfeldern.
Doch es gibt eine Möglichkeit, Daten sofort anzuzeigen, auch wenn FileMaker noch weiterarbeitet: Daten per POST an einen WebViewer übergeben und dort asynchron anzeigen.
Warum nicht einfach FileMaker-Listen?
Standardmäßig lädt FileMaker Listenansichten synchron – das heißt, es wartet, bis alle Datensätze verarbeitet sind. Das führt zu Problemen, wenn: • Tausende Datensätze geladen werden, • FileMaker noch sortiert, • eine Suche viele Treffer hat, • Zusatzinformationen aus mehreren Tabellen geladen werden müssen.
Die Lösung: Daten mit -X POST effizient an eine externe Webanwendung übergeben und dort direkt rendern – unabhängig davon, ob FileMaker noch weiter rechnet.
Datenübergabe aus FileMaker: So geht’s richtig
Wir nutzen den Insert from URL-Befehl, um die Daten per POST an eine Webanwendung zu übergeben. Hierbei setzen wir auf application/x-www-form-urlencoded, da diese Methode stabil mit großen Datenmengen arbeitet.
Set Variable [ $url ; Value: "http://meinserver.de/daten.php" ] Set Variable [ $payload ; Value: "projects=" & $id_projects & "&staff=" & $id_staff & "&anlage=" & $anlage & "&status=" & $status & "&task=" & $id_task & "&image=" & $image & "&inhalt=" & $inhalt & "&historyColors=" & $historyColors & "&planungsmonat=" & $planungsmonat & "&date_von=" & $date_von & "&date_bis=" & $date_bis & "&zeit_von=" & $zeit_von & "&zeit_bis=" & $zeit_bis & "&anzahl_staff=" & $anzahl_staff & "&staff2=" & $id_staff_2 & "&staff3=" & $id_staff_3 & "&erstellt=" & $erstellt & "&prio=" & $prio & "¬es=" & $notes ] Insert from URL [ $url ; "-X POST " & "--header \"Content-Type: application/x-www-form-urlencoded\" " & "--data " & Zitat ( $payload ) ]
Der Vorteil, ich kann unabhängig von URL-Begrenzungen Daten übergeben, ich erspare mir den Aufbau komplexer JSON-Strukturen innerhalb von FileMaker. Datentrennung geschieht bei mir vorzugsweise mit einem Pipe. Es ist natürlich auch anderes möglich. Datensammlung innerhalb von FileMaker über Schleifen, das verspricht bessere Kontrolle oder wenn es mal schnell gehen soll, geht natürlich auch die List-Funktion. Das ist aber Geschmacksache.
Unser PHP-Script empfängt die Daten und kann mit der Verarbeitung beginnen. Sobald die Daten per POST
an PHP gesendet wurden, werden sie in einzelne Arrays zerlegt, sodass sie flexibel weiterverarbeitet werden können. Durch das entdecken von Strings anhand eines Trennzeichens (z. B. |
) lassen sich in einer einzigen Anfrage übertragen:
$projects = isset($_POST['projects']) ? explode('|', $_POST['projects']) : []; $staff = isset($_POST['staff']) ? explode('|', $_POST['staff']) : []; $anlage = isset($_POST['anlage']) ? explode('|', $_POST['anlage']) : []; $status = isset($_POST['status']) ? explode('|', $_POST['status']) : []; $task = isset($_POST['task']) ? explode('|', $_POST['task']) : []; $image = isset($_POST['image']) ? explode('|', $_POST['image']) : []; $inhalt = isset($_POST['inhalt']) ? explode('|', $_POST['inhalt']) : []; $planungsmonat = isset($_POST['planungsmonat']) ? explode('|', $_POST['planungsmonat']) : [];
Die Daten aus PHP werden dann über eine Schleife in HTML überführt. In diesem Beispiel erzeugen wir eine dynamische Tabelle, die aus den übergebenen Daten generiert wird:
<table border="1"> <tr> <th>Projekt</th> <th>Aufgabe</th> <th>Mitarbeiter</th> <th>Status</th> </tr> <?php foreach ($task as $index => $taskName): ?> <tr> <td><?= htmlspecialchars($projects[$index] ?? 'Unbekannt') ?></td> <td><?= htmlspecialchars($taskName) ?></td> <td><?= htmlspecialchars($staff[$index] ?? 'Kein Mitarbeiter') ?></td> <td><?= htmlspecialchars($status[$index] ?? 'Unbekannt') ?></td> </tr> <?php endforeach; ?> </table>
Mit ein wenig CSS kann die Liste angepasst werden, Zwischesortierungen, Statusfarben, nichts was nicht möglich ist.
.task-list { width: calc(100% - 20px); /* Verhindert das Überlaufen nach rechts / max-width: 100%; margin: 10px auto; background: white; padding: 10px; border-radius: 5px; box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2); font-size: 14px; overflow-x: hidden; / Falls nötig, um Überlauf zu vermeiden */ }
.task-group {
margin-top: 15px;
padding: 8px;
background: #3773B5;
font-size: 14px;
font-weight: bold;
color: white;
border-radius: 5px;
text-align: left;
}
.task-item {
width: 98%; /* Damit es nicht über den Container hinausragt */
max-width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 5px 10px;
border-radius: 3px;
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
font-size: 13px;
line-height: 1.2;
background-color: white;
flex-wrap: wrap;
box-sizing: border-box; /* Sorgt dafür, dass Padding berücksichtigt wird */
}
Eine sequentielle Suche, die in ihrer Schnelligkeit niemals in FileMaker abzubilden ist, runden die Tabelle ab.
<script> document.getElementById("taskSearch").addEventListener("keyup", function() { let searchQuery = this.value.toLowerCase(); let taskGroups = document.querySelectorAll(".task-group-container"); let resultCount = 0; // Zähler für die Anzahl der gefundenen Datensätze taskGroups.forEach(group => { let hasMatch = false; let tasks = group.querySelectorAll(".task-item"); tasks.forEach(task => { let text = task.innerText.toLowerCase(); // Gesamten Inhalt durchsuchen if (text.includes(searchQuery)) { task.style.display = ""; // Zeigen hasMatch = true; resultCount++; // Treffer zählen } else { task.style.display = "none"; // Verstecken } }); // Gruppe ausblenden, wenn keine Aufgabe übrig ist group.style.display = hasMatch ? "" : "none"; }); // Anzeige der Trefferanzahl aktualisieren document.getElementById("searchResultsCount").textContent = resultCount + " Ergebnisse gefunden"; }); </script>
Natürlich darf die Möglichkeit aus dem WebViewer heraus mit FileMaker zu kommunizieren nicht fehlen. In diesem Fall noch mit einer Bedingung.
document.addEventListener("DOMContentLoaded", function () { document.querySelectorAll(".status-dropdown").forEach(function (dropdown) { dropdown.addEventListener("change", function () { let taskId = this.getAttribute("data-task-id"); let newStatus = this.value; if (newStatus === "Angebot folgt") { // PopOver anzeigen let modal = document.getElementById("offerModal"); modal.style.display = "flex"; // Speichern-Button im PopOver document.getElementById("confirmOffer").onclick = function () { let priority = document.getElementById("offerPriority").value; let note = document.getElementById("offerNote").value.trim(); if (note === "") { alert(" Bitte eine Notiz eingeben!"); return; } modal.style.display = "none"; // Fenster schließen // FileMaker-Skript aufrufen mit Priorität & Notiz let fileMakerScriptURL = "fmp://$/AVAGmbH?script=UpdateTaskStatus¶m=" + encodeURIComponent(taskId + "|" + newStatus + "|" + priority + "|" + note); console.log(" FileMaker-Skript aufrufen:", fileMakerScriptURL); window.location = fileMakerScriptURL; }; // Abbrechen-Button im PopOver document.getElementById("cancelOffer").onclick = function () { modal.style.display = "none"; // Fenster schließen dropdown.value = "In Planung"; // Status zurücksetzen }; return; // Stoppe die normale Ausführung, solange PopOver offen ist } // Falls NICHT "Angebot folgt", normales Verhalten let fileMakerScriptURL = "fmp://$/AVAGmbH?script=UpdateTaskStatus¶m=" + encodeURIComponent(taskId + "|" + newStatus); console.log("FileMaker-Skript aufrufen:", fileMakerScriptURL); window.location = fileMakerScriptURL; // Seite nach kurzer Verzögerung aktualisieren setTimeout(function () { window.location.reload(); }, 1000); }); }); });
Es gibt unendliche Optimierungsmöglichkeiten. Das wichtigste ist aber, wir können mit recht wenig Aufwand, alte schwergewichtige FileMaker-Anwendungen wieder flott machen.