Zum Hauptinhalt springen
Verwenden Sie dieses Muster, um Twenty mit Produktdaten aus Ihrem Data Warehouse (z. B. Snowflake, BigQuery, PostgreSQL) synchron zu halten.

Workflow-Struktur

  1. Auslöser: Nach Zeitplan
  2. Code: Ihr Data Warehouse abfragen
  3. Code (optional): Daten als Array formatieren
  4. Iterator: Jedes Produkt durchlaufen
  5. Upsert Record: In Twenty erstellen oder aktualisieren

Schritt 1: Auslöser planen

Stellen Sie den Workflow so ein, dass er mit einer Häufigkeit läuft, die Ihren Anforderungen an die Datenaktualität entspricht:
  • Alle 5 Minuten für eine nahezu Echtzeit-Synchronisierung
  • Stündlich für weniger kritische Daten
  • Täglich für Batch-Updates

Schritt 2: Ihr Data Warehouse abfragen

Fügen Sie eine Code-Aktion hinzu, um aktuelle Daten abzurufen:
export const main = async () => {
  const intervalMinutes = 10; // Match your schedule frequency
  const cutoffTime = new Date(Date.now() - intervalMinutes * 60 * 1000).toISOString();

  // Replace with your actual data warehouse connection
  const response = await fetch("https://your-warehouse-api.com/query", {
    method: "POST",
    headers: {
      "Authorization": "Bearer YOUR_API_KEY",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      query: `
        SELECT id, name, sku, price, stock_quantity, updated_at
        FROM products
        WHERE updated_at >= '${cutoffTime}'
      `
    })
  });

  const data = await response.json();
  return { products: data.results };
};
Filtern Sie nach updated_at >= last X minutes, um nur kürzlich geänderte Datensätze abzurufen. So bleibt die Synchronisierung effizient.

Schritt 3: Daten formatieren (optional)

Wenn Ihr Data Warehouse Daten in einem Format zurückgibt, das transformiert werden muss, fügen Sie eine weitere Code-Aktion hinzu. Häufige Transformationen umfassen Typkonvertierungen, Feldumbenennungen und Datenbereinigung.

Beispiel: Benutzerdaten mit booleschen und Statusfeldern

export const main = async (params: {
  users: any;
}): Promise<object> => {
  const { users } = params;
  const usersFormatted = typeof users === "string" ? JSON.parse(users) : users;

  // Convert string "true"/"false" to actual booleans
  const toBool = (v: any) => v === true || v === "true";

  return {
    users: usersFormatted.map((user) => ({
      ...user,
      activityStatus: String(user.activityStatus).toUpperCase(),
      isActiveLast30d: toBool(user.isActiveLast30d),
      isActiveLast7d: toBool(user.isActiveLast7d),
      isActiveLast24h: toBool(user.isActiveLast24h),
      isTwenty: toBool(user.isTwenty),
    })),
  };
};

Beispiel: Produktdaten mit Typkonvertierungen

export const main = async (params: { products: any }) => {
  const products = typeof params.products === "string"
    ? JSON.parse(params.products)
    : params.products;

  return {
    products: products.map(product => ({
      externalId: product.id,
      name: product.name,
      sku: product.sku,
      price: parseFloat(product.price),        // String → Number
      stockQuantity: parseInt(product.stock_quantity),
      isActive: product.status === "active"    // String → Boolean
    }))
  };
};

Beispiel: Datums- und Währungsformatierung

export const main = async (params: { deals: any }) => {
  const deals = typeof params.deals === "string"
    ? JSON.parse(params.deals)
    : params.deals;

  return {
    deals: deals.map(deal => ({
      ...deal,
      // Convert Unix timestamp to ISO date
      closedAt: deal.closed_timestamp
        ? new Date(deal.closed_timestamp * 1000).toISOString()
        : null,
      // Ensure amount is a number (remove currency symbols)
      amount: parseFloat(String(deal.amount).replace(/[^0-9.-]/g, "")),
      // Normalize stage names
      stage: deal.stage?.toLowerCase().replace(/_/g, " ")
    }))
  };
};

Häufige Transformationen

QuellformatZielformatCode
"true" / "false"true / falsev === true || v === "true"
"123.45"123.45parseFloat(value)
"active""ACTIVE"value.toUpperCase()
1704067200 (Unix)ISO-Datumnew Date(v * 1000).toISOString()
"$1,234.56"1234.56parseFloat(v.replace(/[^0-9.-]/g, ""))
null / undefined""value || ""

Schritt 4: Durch die Produkte iterieren

Fügen Sie eine Iterator-Aktion hinzu:
  • Eingabe: {{code.products}}
Dies durchläuft jedes Produkt im Array.

Schritt 5: Jeden Datensatz upserten

Fügen Sie innerhalb des Iterators eine Upsert Record-Aktion hinzu:
EinstellungWert
ObjektIhr benutzerdefiniertes Produktobjekt
Abgleichen anhandExterne ID oder SKU (eindeutiger Bezeichner)
Name{{iterator.item.name}}
SKU{{iterator.item.sku}}
Preis{{iterator.item.price}}
Verwenden Sie Upsert (aktualisieren oder erstellen), anstatt separate Verzweigungen für Erstellen vs. Aktualisieren zu bauen. Das ist schneller aufzubauen und leichter zu debuggen.

Beispielanwendungsfälle

QuelleDaten
ERP-SystemProduktkatalog, Preise, Bestand
E-Commerce-PlattformBestellungen, Kunden, Produktaktualisierungen
Data WarehouseAggregierte Metriken, angereicherte Daten
BestandsverwaltungssystemBestandsmengen, Nachbestellwarnungen

Verwandt