INTEGRITY Dokumentace

Hromadný import do D1 pomocí REST API

V tomto tutoriálu se naučíte, jak importovat databázi do D1 pomocí REST API.

Předpoklady

  1. Zaregistrujte si účet Cloudflare.
  2. Nainstalujte Node.js.

Správce verzí Node.js

Použijte správce verzí Node, jako je Volta nebo nvm abyste se vyhnuli problémům s oprávněními a mohli měnit verze Node.js. Wrangler, o kterém se dozvíte dále v této příručce, vyžaduje verzi Node 16.17.0 nebo novější.

1. Vytvořte token API D1

Pro použití REST API musíte vygenerovat API token pro ověřování API požadavků. To můžete provést přes Cloudflare dashboard.

  1. V dashboardu Cloudflare přejděte na API Tokens stránce.

    Přejděte na API tokeny účtu ↗
  2. V části API Tokens, vyberte Create Token.

  3. Přejděte na Custom token > Create custom token, pak vyberte Začínáme.

  4. V části Název tokenu, zadejte popisný název tokenu. Například Name-D1-Import-API-Token.

  5. V části Oprávnění:

    • Vyberte Účet.
    • Vyberte D1.
    • Vyberte Úprava.
  6. Vyberte Pokračovat k souhrnu.

  7. Vyberte Vytvoření tokenu.

  8. Zkopírujte API token a uložte jej do zabezpečeného souboru.

2. Vytvořte cílovou tabulku

Musíte mít existující tabulku D1, jejíž schéma odpovídá datům, která chcete importovat.

Tento tutoriál používá následující:

Chcete-li vytvořit tabulku, postupujte podle následujících kroků:

  1. V dashboardu Cloudflare přejděte na D1 stránce.

    Přejděte na SQL databáze D1 ↗
  2. Vyberte Create database.

  3. Pojmenujte databázi. Pro účely tohoto tutoriálu pojmenujte databázi D1 d1-import-tutorial.

  4. (Volitelné) Zadejte location hint. Location hint je volitelný parametr, kterým můžete určit požadované geografické umístění vaší databáze. Více informací najdete v Zadejte nápovědu umístění s dalšími informacemi.

  5. Vyberte Vytvořit.

  6. Přejděte na Konzole, poté vložte následující úryvek SQL. Tím se vytvoří tabulka s názvem TargetD1Table.

    DROP TABLE IF EXISTS TargetD1Table;
    CREATE TABLE IF NOT EXISTS TargetD1Table (id INTEGER PRIMARY KEY, text TEXT, date_added TEXT);

    Alternativně můžete použít Wrangler CLI.

    # Create a D1 database
    npx wrangler d1 create d1-import-tutorial
    
    # Create a D1 table
    npx wrangler d1 execute d1-import-tutorial --command="DROP TABLE IF EXISTS TargetD1Table; CREATE TABLE IF NOT EXISTS TargetD1Table (id INTEGER PRIMARY KEY, text TEXT, date_added TEXT);" --remote

3. Vytvořte index.js soubor

  1. Vytvořte nový adresář a inicializujte v něm nový projekt Node.js.

    mkdir d1-import-tutorial
    cd d1-import-tutorial
    npm init -y
  2. V tomto repozitáři vytvořte nový soubor s názvem index.js. Tento soubor bude obsahovat kód, který pomocí REST API importuje vaše data do databáze D1.

  3. Ve vašem index.js soubor a definujte následující proměnné:

    • TARGET_TABLE: Název cílové tabulky
    • ACCOUNT_ID: ID účtu. Viz Podrobnosti o účtu v Workers & Pages.
    • DATABASE_ID: ID databáze D1. Toto ID najdete na stránce vaší databáze.
    • D1_API_KEY: D1 API token vygenerovaný v krok 1
    index.js
    const TARGET_TABLE = " "; // for the tutorial, `TargetD1Table`
    const ACCOUNT_ID = " ";
    const DATABASE_ID = " ";
    const D1_API_KEY = " ";
    const D1_URL = `https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/d1/database/${DATABASE_ID}/import`;
    const filename = crypto.randomUUID(); // create a random filename
    const uploadSize = 500;
    const headers = {
    	"Content-Type": "application/json",
    	Authorization: `Bearer ${D1_API_KEY}`,
    };

4. Vygenerujte ukázková data (volitelné)

V praxi již pravděpodobně máte data, která chcete do databáze D1 importovat.

Tento tutoriál generuje ukázková data pro demonstraci procesu importu.

  1. Nainstalujte @faker-js/faker modul.

    npm i @faker-js/faker
  2. Následující kód přidejte na začátek souboru index.js soubor. Tento kód vytvoří pole s názvem data s 2500 (uploadSize) prvků pole, kde každý prvek pole obsahuje objekt s id, text, a date_added. Každý prvek pole odpovídá řádku tabulky.

    index.js
    import crypto from "crypto";
    import { faker } from "@faker-js/faker";
    
    // Generate Fake data
    const data = Array.from({ length: uploadSize }, () => ({
    	id: Math.floor(Math.random() * 1000000),
    	text: faker.lorem.paragraph(),
    	date_added: new Date().toISOString().slice(0, 19).replace("T", " "),
    }));

5. Vygenerujte příkaz SQL

  1. Vytvořte funkci, která vygeneruje příkaz SQL pro vložení dat do cílové tabulky. Tato funkce využívá data pole vygenerované v předchozím kroku.

    index.js
    function makeSqlInsert(data, tableName, skipCols = []) {
    	const columns = Object.keys(data[0]).join(",");
    	const values = data
    		.map((row) => {
    			return (
    				"(" +
    				Object.values(row)
    					.map((val) => {
    						if (skipCols.includes(val) || val === null || val === "") {
    							return "NULL";
    						}
    						return `'${String(val).replace(/'/g, "").replace(/"/g, "'")}'`;
    					})
    					.join(",") +
    				")"
    			);
    		})
    		.join(",");
    
    	return `INSERT INTO ${tableName} (${columns}) VALUES ${values};`;
    }

6. Importujte data do D1

Proces importu se skládá ze čtyř kroků:

  1. Init upload: Tento krok zahájí proces nahrávání. Odešle hash SQL příkazu do D1 API a obdrží URL pro nahrání.
  2. Nahrát do R2: Tento krok nahraje SQL příkaz na URL pro nahrání.
  3. Spustit import: Tento krok spustí proces příjmu dat.
  4. Dotazování: Tento krok periodicky kontroluje proces importu, dokud není dokončen.
  1. Vytvořte funkci s názvem uploadToD1 která provede čtyři kroky procesu importu.

    index.js
    async function uploadToD1() {
    	// 1. Init upload
    	const hashStr = crypto.createHash("md5").update(sqlInsert).digest("hex");
    
    	try {
    		const initResponse = await fetch(D1_URL, {
    			method: "POST",
    			headers,
    			body: JSON.stringify({
    				action: "init",
    				etag: hashStr,
    			}),
    		});
    
    		const uploadData = await initResponse.json();
    		const uploadUrl = uploadData.result.upload_url;
    		const filename = uploadData.result.filename;
    
    		// 2. Upload to R2
    		const r2Response = await fetch(uploadUrl, {
    			method: "PUT",
    			body: sqlInsert,
    		});
    
    		const r2Etag = r2Response.headers.get("ETag").replace(/"/g, "");
    
    		// Verify etag
    		if (r2Etag !== hashStr) {
    			throw new Error("ETag mismatch");
    		}
    
    		// 3. Start ingestion
    		const ingestResponse = await fetch(D1_URL, {
    			method: "POST",
    			headers,
    			body: JSON.stringify({
    				action: "ingest",
    				etag: hashStr,
    				filename,
    			}),
    		});
    
    		const ingestData = await ingestResponse.json();
    		console.log("Ingestion Response:", ingestData);
    
    		// 4. Polling
    		await pollImport(ingestData.result.at_bookmark);
    
    		return "Import completed successfully";
    	} catch (e) {
    		console.error("Error:", e);
    		return "Import failed";
    	}
    }

    Ve výše uvedeném kódu:

    • md5 se vygeneruje hash SQL příkazu.
    • initResponse inicializuje proces nahrávání a přijímá URL adresu pro nahrávání.
    • r2Response nahraje příkaz SQL na adresu URL pro nahrání.
    • Před zahájením importu se ověří ETag.
    • ingestResponse zahajuje proces importu.
    • pollImport kontroluje proces importu, dokud není dokončen.
  2. Přidejte pollImport funkci do index.js .

    index.js
    async function pollImport(bookmark) {
    	const payload = {
    		action: "poll",
    		current_bookmark: bookmark,
    	};
    
    	while (true) {
    		const pollResponse = await fetch(D1_URL, {
    			method: "POST",
    			headers,
    			body: JSON.stringify(payload),
    		});
    
    		const result = await pollResponse.json();
    		console.log("Poll Response:", result.result);
    
    		const { success, error } = result.result;
    
    		if (
    			success ||
    			(!success && error === "Not currently importing anything.")
    		) {
    			break;
    		}
    
    		await new Promise((resolve) => setTimeout(resolve, 1000));
    	}
    }

    Výše uvedený kód provádí následující:

    • Odesílá poll akci do API D1.
    • Opakovaně kontroluje proces importu, dokud se nedokončí.
  3. Nakonec přidejte runImport funkci do index.js soubor pro spuštění procesu importu.

    index.js
    async function runImport() {
    	const result = await uploadToD1();
    	console.log(result);
    }
    
    runImport();

7. Napište finální kód

V předchozích krocích jste vytvořili funkce, které provádějí různé procesy potřebné pro import dat do D1. Závěrečný kód tyto funkce spustí a naimportuje ukázková data do cílové tabulky D1.

  1. Zkopírujte konečný kód svého index.js soubor tak, jak je uvedeno níže, přičemž vaše proměnné definujte na začátku kódu.

    import crypto from "crypto";
    import { faker } from "@faker-js/faker";
    
    const TARGET_TABLE = "";
    const ACCOUNT_ID = "";
    const DATABASE_ID = "";
    const D1_API_KEY = "";
    const D1_URL = `https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/d1/database/${DATABASE_ID}/import`;
    const uploadSize = 500;
    const headers = {
    	"Content-Type": "application/json",
    	Authorization: `Bearer ${D1_API_KEY}`,
    };
    
    // Generate Fake data
    const data = Array.from({ length: uploadSize }, () => ({
    	id: Math.floor(Math.random() * 1000000),
    	text: faker.lorem.paragraph(),
    	date_added: new Date().toISOString().slice(0, 19).replace("T", " "),
    }));
    
    // Make SQL insert statements
    function makeSqlInsert(data, tableName, skipCols = []) {
    	const columns = Object.keys(data[0]).join(",");
    	const values = data
    		.map((row) => {
    			return (
    				"(" +
    				Object.values(row)
    					.map((val) => {
    						if (skipCols.includes(val) || val === null || val === "") {
    							return "NULL";
    						}
    						return `'${String(val).replace(/'/g, "").replace(/"/g, "'")}'`;
    					})
    					.join(",") +
    				")"
    			);
    		})
    		.join(",");
    
    	return `INSERT INTO ${tableName} (${columns}) VALUES ${values};`;
    }
    
    const sqlInsert = makeSqlInsert(data, TARGET_TABLE);
    
    async function pollImport(bookmark) {
    	const payload = {
    		action: "poll",
    		current_bookmark: bookmark,
    	};
    
    	while (true) {
    		const pollResponse = await fetch(D1_URL, {
    			method: "POST",
    			headers,
    			body: JSON.stringify(payload),
    		});
    
    		const result = await pollResponse.json();
    		console.log("Poll Response:", result.result);
    
    		const { success, error } = result.result;
    
    		if (
    			success ||
    			(!success && error === "Not currently importing anything.")
    		) {
    			break;
    		}
    
    		await new Promise((resolve) => setTimeout(resolve, 1000));
    	}
    }
    
    // Upload to D1
    async function uploadToD1() {
    	// 1. Init upload
    	const hashStr = crypto.createHash("md5").update(sqlInsert).digest("hex");
    
    	try {
    		const initResponse = await fetch(D1_URL, {
    			method: "POST",
    			headers,
    			body: JSON.stringify({
    				action: "init",
    				etag: hashStr,
    			}),
    		});
    
    		const uploadData = await initResponse.json();
    		const uploadUrl = uploadData.result.upload_url;
    		const filename = uploadData.result.filename;
    
    		// 2. Upload to R2
    		const r2Response = await fetch(uploadUrl, {
    			method: "PUT",
    			body: sqlInsert,
    		});
    
    		const r2Etag = r2Response.headers.get("ETag").replace(/"/g, "");
    
    		// Verify etag
    		if (r2Etag !== hashStr) {
    			throw new Error("ETag mismatch");
    		}
    
    		// 3. Start ingestion
    		const ingestResponse = await fetch(D1_URL, {
    			method: "POST",
    			headers,
    			body: JSON.stringify({
    				action: "ingest",
    				etag: hashStr,
    				filename,
    			}),
    		});
    
    		const ingestData = await ingestResponse.json();
    		console.log("Ingestion Response:", ingestData);
    
    		// 4. Polling
    		await pollImport(ingestData.result.at_bookmark);
    
    		return "Import completed successfully";
    	} catch (e) {
    		console.error("Error:", e);
    		return "Import failed";
    	}
    }
    
    async function runImport() {
    	const result = await uploadToD1();
    	console.log(result);
    }
    
    runImport();

8. Spusťte kód

  1. Spusťte svůj kód.

    node index.js

Nyní uvidíte cílovou tabulku D1 naplněnou ukázkovými daty.

Souhrn

Dokončením tohoto výukového kurzu jste

  1. Vytvořen API token.
  2. Vytvořena cílová databáze a tabulka.
  3. Vygenerovaná ukázková data.
  4. Vytvořen příkaz SQL pro ukázková data.
  5. Import ukázkových dat do cílové tabulky D1 pomocí REST API.