Zum Inhalt

Datensätze

Mit forms liest und schreibst du Datensätze anderer Formulare — ganz ohne SQL. Ein Datensatz ist dabei einfach ein Objekt mit den Feldnamen: { kunde: "Meyer", betrag: 120 }.

Ausführliches dazu: forms — Datensätze per Skript.

Das Übungsformular

Die Beispiele arbeiten mit einem Formular uebung_bestellung. Wer mitmachen will, legt es im Formular-Editor mit diesen Feldern an:

Feld Typ Hinweis
kunde Text Pflichtfeld
betrag Zahl
status Auswahl neu, freigegeben, erledigt
datum Datum
positionen Detail-Tabelle Spalten artikel (Text), menge (Ganzzahl), preis (Zahl)

forms arbeitet immer mit der Formular-ID (hier uebung_bestellung) und der Datensatz-Nummer (id).

Einsteiger

1. Einen Datensatz anlegen

forms.create speichert einen neuen Datensatz und gibt seine Nummer zurück.

var id = forms.create("uebung_bestellung", {
  kunde:  "Meyer",
  betrag: 120,
  status: "neu",
  datum:  "2026-09-01"
});
log.info("Neuer Datensatz Nr. " + id);

2. Einen Datensatz lesen

forms.get holt einen Datensatz über seine Nummer.

var id = forms.create("uebung_bestellung", { kunde: "Schulz", betrag: 75.5, status: "neu" });

var satz = forms.get("uebung_bestellung", id);
log.info("Kunde " + satz.kunde + ", Betrag " + satz.betrag);

3. Gibt es den Datensatz?

log.info("Nr. 999999 gibt es: " + forms.exists("uebung_bestellung", 999999));

4. Wenn es den Datensatz nicht gibt

Statt eines Fehlers liefert forms.get dann null. Prüfe das, bevor du auf Felder zugreifst.

var satz = forms.get("uebung_bestellung", 999999);
if (satz == null) {
  log.info("Datensatz nicht gefunden");
} else {
  log.info("Kunde: " + satz.kunde);
}

5. Alle Datensätze zählen

forms.list liefert alle Datensätze als Liste.

var alle = forms.list("uebung_bestellung");
log.info(alle.length + " Datensätze vorhanden");

6. Einen Wert ändern

forms.update ändert nur die Felder, die du angibst. Alles andere bleibt, wie es ist.

var id = forms.create("uebung_bestellung", { kunde: "Wagner", betrag: 40, status: "neu" });

forms.update("uebung_bestellung", id, { status: "freigegeben" });

var satz = forms.get("uebung_bestellung", id);
log.info("Status jetzt: " + satz.status + ", Betrag weiter: " + satz.betrag);

7. Einen Datensatz löschen

var id = forms.create("uebung_bestellung", { kunde: "Löschtest" });

forms.delete("uebung_bestellung", id);
log.info("noch da: " + forms.exists("uebung_bestellung", id));

8. Alle Datensätze durchlaufen

forms.forEach ruft deine Funktion für jeden Datensatz einmal auf.

var summe = 0;
forms.forEach("uebung_bestellung", function (satz) {
  summe += satz.betrag || 0;           // leere Beträge zählen als 0
});
log.info("Gesamtbetrag: " + summe);

Fortgeschritten

9. Mit Positionen anlegen

Die Zeilen einer Detail-Tabelle gibst du als Liste von Objekten mit.

var id = forms.create("uebung_bestellung", {
  kunde:  "Becker",
  status: "neu",
  positionen: [
    { artikel: "Stift", menge: 10, preis: 1.20 },
    { artikel: "Block", menge: 5,  preis: 2.50 },
    { artikel: "Ordner", menge: 2, preis: 3.90 }
  ]
});
var satz = forms.get("uebung_bestellung", id);
log.info("Bestellung " + id + " mit " + satz.positionen.length + " Positionen");

10. Positionen auswerten

forms.get liefert die Detail-Zeilen mit. So rechnest du die Summe aus.

var id = forms.create("uebung_bestellung", {
  kunde: "Hoffmann",
  positionen: [
    { artikel: "Stift", menge: 10, preis: 1.20 },
    { artikel: "Block", menge: 5,  preis: 2.50 },
    { artikel: "Ordner", menge: 3, preis: 4.20 }
  ]
});

var summe = 0;
forms.get("uebung_bestellung", id).positionen.forEach(function (p) {
  summe += p.menge * p.preis;
});
log.info("Summe: " + summe.toFixed(2));

list ohne Positionen

forms.list lässt die Detail-Zeilen weg, damit lange Listen schnell bleiben. Brauchst du sie, holst du den einzelnen Satz mit forms.get.

11. Nur bestimmte Datensätze

forms.list liefert alles — aussuchen kannst du mit filter.

var neue = forms.list("uebung_bestellung").filter(function (s) {
  return s.status === "neu";
});
log.info(neue.length + " neue Bestellungen");

12. Die drei größten Bestellungen

var liste = forms.list("uebung_bestellung")
  .filter(function (s) { return s.betrag != null; })
  .sort(function (a, b) { return b.betrag - a.betrag; })   // größter zuerst
  .slice(0, 3);

liste.forEach(function (s, i) {
  log.info((i + 1) + ". " + s.kunde + ": " + s.betrag + " €");
});

13. Vorher prüfen

forms.validate prüft Werte gegen das Formular — ohne zu speichern. Eine leere Liste bedeutet: alles in Ordnung.

var fehler = forms.validate("uebung_bestellung", {
  betrag: "zwölf",           // keine Zahl
  status: "unbekannt"        // nicht in der Auswahl
  // kunde fehlt, ist aber Pflicht
});
log.info("Probleme: " + fehler.length);
fehler.forEach(function (f) {
  log.info("- " + f.field + ": " + f.message);
});

14. Nur speichern, wenn alles stimmt

Mit { validate: true } bricht create bei Fehlern ab — gespeichert wird dann nichts.

try {
  forms.create("uebung_bestellung", { betrag: 10 }, { validate: true });
  log.info("Gespeichert");
} catch (e) {
  log.info("Nicht gespeichert: " + e.message);
}

15. Eingaben aus dem aktuellen Formular übernehmen

Ein Button-Skript legt aus den Eingaben eine Bestellung an.

var id = forms.create("uebung_bestellung", {
  kunde:  ctx.form.name,
  betrag: ctx.form.betrag,
  status: "neu",
  datum:  new Date().format("yyyy-MM-dd")
});
ctx.form.ergebnis = "Bestellung " + id;
log.info("Bestellung für " + ctx.form.name + " angelegt");

16. Mehrere Datensätze auf einmal ändern

var geaendert = 0;
forms.list("uebung_bestellung").forEach(function (s) {
  if (s.status === "neu" && s.betrag != null && s.betrag < 100) {
    geaendert += forms.update("uebung_bestellung", s.id, { status: "freigegeben" });
  }
});
log.info(geaendert + " kleine Bestellungen freigegeben");

update gibt zurück, wie viele Datensätze geändert wurden (0 oder 1).

17. Wem gehört der Datensatz?

Normalerweise gehört ein neuer Datensatz dem angemeldeten Benutzer. Beim Import legst du mit owner einen anderen Eigentümer fest.

var id = forms.create("uebung_bestellung",
  { kunde: "Import GmbH", status: "neu" },
  { owner: "import" });

var nurMeine = forms.get("uebung_bestellung", id, { scope: "mine" });
log.info("Eigentümer: import – für mich sichtbar mit scope 'mine': " + (nurMeine != null));

scope: "mine" beschränkt Lesen, Ändern und Löschen auf die eigenen Datensätze. Ohne diese Angabe sieht ein Skript alle.

Profi

18. Import aus einer CSV-Datei

Zeile für Zeile prüfen und anlegen. Fehlerhafte Zeilen werden gesammelt statt den ganzen Import abzubrechen.

var text = "kunde;betrag;status\n"
         + "Nord GmbH;250;neu\n"
         + ";90;neu\n"                        // Kunde fehlt → abweisen
         + "Süd AG;1200;freigegeben\n";

var angelegt = 0, abgewiesen = [];
var zeilen = csv.parse(text, { separator: ";", header: true });
// Indizierte Schleife wegen der Zeilennummer — forEach gibt auf einer
// Host-Liste keinen Index her.
for (var i = 0; i < zeilen.length; i++) {
  var zeile = zeilen[i];
  var werte = {
    kunde:  zeile.kunde,
    betrag: Number(zeile.betrag),
    status: zeile.status
  };
  var fehler = forms.validate("uebung_bestellung", werte);
  if (fehler.length === 0) {
    forms.create("uebung_bestellung", werte, { owner: "import" });
    angelegt++;
  } else {
    abgewiesen.push("Zeile " + (i + 2) + ": " + fehler[0].message);
  }
}
log.info(angelegt + " angelegt, " + abgewiesen.length + " abgewiesen");
abgewiesen.forEach(function (m) { log.info(m); });

19. Anlegen oder aktualisieren

Gibt es den Kunden schon, wird sein Satz geändert — sonst neu angelegt. So entstehen bei einem wiederholten Import keine doppelten Einträge.

function speichere(werte) {
  var vorhanden = forms.list("uebung_bestellung").filter(function (s) {
    return s.kunde === werte.kunde;
  })[0];
  if (vorhanden) {
    forms.update("uebung_bestellung", vorhanden.id, werte);
    return "aktualisiert";
  }
  forms.create("uebung_bestellung", werte);
  return "neu angelegt";
}

log.info("erster Lauf: "  + speichere({ kunde: "Einmalig KG", betrag: 10 }));
log.info("zweiter Lauf: " + speichere({ kunde: "Einmalig KG", betrag: 20 }));

20. Positionen ersetzen

Gibst du bei update eine Positionsliste mit, ersetzt sie die bisherige vollständig.

var id = forms.create("uebung_bestellung", {
  kunde: "Umbau AG",
  positionen: [{ artikel: "Stift", menge: 1, preis: 1 }, { artikel: "Block", menge: 1, preis: 2 }]
});
var vorher = forms.get("uebung_bestellung", id).positionen.length;

forms.update("uebung_bestellung", id, {
  positionen: [{ artikel: "Drucker", menge: 1, preis: 199 }]
});

var nachher = forms.get("uebung_bestellung", id).positionen;
log.info("vorher " + vorher + ", nachher " + nachher.length + ": " + nachher[0].artikel);

21. Einen Datensatz kopieren

Ohne id und mit neuem Status wird aus einer alten Bestellung eine neue.

var original = forms.create("uebung_bestellung", {
  kunde: "Stammkunde", betrag: 55, status: "erledigt",
  positionen: [{ artikel: "Toner", menge: 1, preis: 55 }]
});

var vorlage = forms.get("uebung_bestellung", original);
var kopie = {
  kunde:  vorlage.kunde,
  betrag: vorlage.betrag,
  status: "neu",
  datum:  new Date().format("yyyy-MM-dd"),
  positionen: vorlage.positionen.map(function (p) {
    return { artikel: p.artikel, menge: p.menge, preis: p.preis };   // ohne interne Nummern
  })
};
var neu = forms.get("uebung_bestellung", forms.create("uebung_bestellung", kopie));
log.info("Kopie hat " + neu.positionen.length + " Positionen, Status " + neu.status);

22. Umsatz je Kunde

Gruppieren mit einem Objekt als „Sammelbehälter".

var jeKunde = {};
forms.forEach("uebung_bestellung", function (s) {
  if (s.betrag == null) return;
  jeKunde[s.kunde] = (jeKunde[s.kunde] || 0) + s.betrag;
});

Object.keys(jeKunde).sort().forEach(function (kunde) {
  log.info(kunde + ": " + jeKunde[kunde]);
});

23. Ergebnis als Tabelle ins Formular

Eine Übersicht wird zur Detail-Tabelle im aktuellen Formular — etwa in einem Bericht-Formular mit einer Tabelle positionen.

ctx.form.positionen = forms.list("uebung_bestellung")
  .filter(function (s) { return s.status === "freigegeben"; })
  .map(function (s) {
    return { artikel: s.kunde, menge: 1, preis: s.betrag };
  });
log.info(ctx.form.positionen.length + " Zeilen in der Übersicht");

24. Viele Datensätze: lieber mit SQL

forms ist bequem, holt aber jeden Datensatz einzeln ins Skript. Für Auswertungen über Tausende Sätze ist SQL schneller. Die Tabelle heißt form_ + Formular-ID.

var r = db.query(
  "SELECT status, COUNT(*) AS anzahl, SUM(betrag) AS summe " +
  "FROM form_uebung_bestellung GROUP BY status ORDER BY status");
r.forEach(function (z) {
  log.info(z.status + " – Anzahl: " + z.anzahl + ", Summe: " + z.summe);
});

Für Änderungen bleibt forms die bessere Wahl: Es kümmert sich um Positionen, Anlagen und Änderungsprotokoll.

25. Aufräumen

Erledigte Bestellungen löschen — forms.delete entfernt auch die Positionen, Dateianlagen und das Änderungsprotokoll.

var geloescht = 0;
forms.list("uebung_bestellung").forEach(function (s) {
  if (s.status === "erledigt") {
    geloescht += forms.delete("uebung_bestellung", s.id);
  }
});
log.info(geloescht + " erledigte Bestellungen gelöscht");