Import/export — din data ut och in, som CSV eller JSON
På Zkrinet: lägg till blocket under Byggblock i panelen — ett klick, din egen kod rörs inte och en ögonblicksbild tas först. Installationsstegen nedan gäller om du kör PocketBase själv, till exempel efter en export.
Frihetsprincipen i ett plugin: en superuser kan ta ut en hel samling som CSV (öppnas i Excel/Numbers/Google Kalkylark) eller JSON — och läsa in den igen, eller läsa in data från ett kalkylark. Importen är allt eller inget: blir en rad fel sparas ingenting.
Validering och sparande är PocketBases egna ($app.save i en transaktion) — samma kontroller som när du sparar i adminpanelen.
Testat mot PocketBase 0.40.4.
#Installation
Kopiera pb_hooks/ till din PocketBase och starta om. Pluginet har inga egna samlingar.
#Exportera
GET /api/zk/export/{samling}?format=csv|json (superuser)
| Parameter | Standard | |
|---|---|---|
format | csv | csv eller json |
avgransare | komma | semikolon ger ; — det Excel med svenska inställningar väntar sig |
dolda | av | 1 = ta med fält som är markerade som dolda. Lösenordshashar och tokenKey följer aldrig med, inte ens då. |
- CSV: UTF-8 med BOM (så att Excel visar å, ä, ö rätt), radslut CRLF, första raden = fältnamn. Värden med komma, semikolon, citattecken eller radbrytning citeras enligt RFC 4180 (
"säger ""hej"""). - JSON: en lista med objekt, värden i sina riktiga typer (tal, sant/falskt, listor, JSON-fält som JSON).
- Relationer blir id:n. Filfält blir filnamn (filerna själva följer inte med). Fleraval (relationer, val, filer) blir i CSV en JSON-lista:
["a","b"]. - Skydd mot formelinjektion: en textcell som börjar med
=,+,-,@, tab eller'får ett'först i CSV:n, så att Excel visar den som text i stället för att köra den som formel. Importen tar bort det igen — en rundresa ger samma värde.
// Från appen (superuser inloggad) — t.ex. en "Ladda ner"-knapp i en adminvy
const csv = await fetch(`${pb.baseURL}/api/zk/export/kunder?format=csv&avgransare=semikolon`, {
headers: { Authorization: pb.authStore.token },
}).then((r) => r.blob())
#Importera
POST /api/zk/import/{samling}?lage=skapa|uppsert&prova=1 (superuser)
Content-Type: text/csv → kroppen är CSV
Content-Type: application/json → kroppen är [ {...}, ... ] eller { "lage": "...", "prova": true, "poster": [ ... ] }
const fil = input.files[0] // en .csv från Excel
const svar = await fetch(`${pb.baseURL}/api/zk/import/kunder?lage=uppsert&prova=1`, {
method: "POST",
headers: { Authorization: pb.authStore.token, "Content-Type": "text/csv" },
body: await fil.text(),
}).then((r) => r.json())
// { ok: true, lage: "uppsert", prova: true, rader: 120, skapade: 100, uppdaterade: 20, fel: [] }
// eller { ok: false, ..., fel: [ { rad: 7, fel: "epost: Must be a valid email address." } ] }
lage=skapa (standard) | Varje rad blir en ny post. En rad med ett id som redan finns är ett fel. |
lage=uppsert | Rad med ett id som finns → posten uppdateras (bara kolumnerna i filen ändras). Annars skapas den. |
prova=1 | Torrkörning: allt valideras och provsparas i transaktionen — även unika nycklar — och rullas sedan alltid tillbaka. Sparar ingenting. |
- Allt eller inget: hela importen körs i en transaktion. Ett enda fel → ingenting sparas, och svaret listar felen (upp till 100) med radnummer: i CSV raden i kalkylarket (rubriken är rad 1, första dataraden rad 2), i JSON postens plats i listan (1 = första).
idfår anges (behålls — så relationer mellan samlingar håller vid en rundresa) eller utelämnas (PocketBase skapar ett).- Avgränsare gissas ur rubrikraden (
,eller;). BOM tas bort. - Värden i CSV: tal med punkt eller komma (
3,5); sant/falskt somtrue/false,1/0,ja/nej,sant/falskt(tom = falskt); fleraval som JSON-lista eller kommaseparerat (a,b); JSON-fält som JSON; datum som PocketBase-datum (2026-11-07 12:00:00.000Z). - Felaktiga värden avvisas med ett läsbart fel. (PocketBase själv gör annars tyst
"abc"till 0 i ett talfält,"kanske"till falskt och ett ogiltigt datum till tomt — vi har mätt det, och importen tillåter det inte.) - Okända kolumner stoppar hela filen innan något görs (troligen fel samling eller felstavat fält). Dubbla eller tomma kolumnnamn likaså.
- Användare (auth-samlingar): kolumnen
passwordsätter ett lösenord (hashas av PocketBase). Saknas den får kontot ett slumpat lösenord, och användaren väljer ett eget via "glömt lösenord".tokenKeykan inte importeras. - Ignoreras vid import: autodatum (
created/updatedoch liknande sätts av PocketBase) och filfält (filnamn kan inte bli filer; viduppsertlämnas befintliga filer orörda).
#Säkerhet
- Båda rutterna kräver superuser. Gäster och vanliga användare får 401/403.
- Systemsamlingar nekas (
_superusers,_otps,_mfas,_externalAuths,_authOrigins…), både via namn och via id. - Append-only-loggar kan inte importeras till (
zk_granskning,zk_gdpr_samtycken) — det vore att förfalska dem. De går att exportera. - Vyer kan exporteras men inte importeras till.
- Dolda fält följer bara med när du ber om det (
dolda=1), lösenordshashar ochtokenKeyaldrig. En CSV med dolda fält på din dator är lika känslig som databasen — behandla den så.
#Tak
| Importkropp | 10 MiB. Servern läser högst så mycket och svarar 413 (mycket större kroppar kan få anslutningen stängd i stället). |
| Rader per import | 10 000 (413 över det) |
| Poster per export | 100 000 (413 — exportera i sidor via PocketBase vanliga API i stället) |
| Rapporterade radfel | 100, sedan avbryts valideringen (fler_fel: true) |
Exporten och importen byggs i minnet. Större flyttar: dela upp filen.
#Begränsningar — läs innan du lovar en kund något
- Filerna följer inte med — bara filnamnen. Att flytta filer är en separat sak (t.ex. kopiera
pb_data/storageeller S3-hinken). created/updatedsätts om vid import. Övriga fält (ochid) blir identiska vid en rundresa, testat med svenska tecken, emoji, citattecken, radbrytningar, komma och semikolon.- API-reglerna (
createRulem.fl.) prövas inte — importen körs som superuser. Fältens validering (obligatoriskt, mönster, min/max, unikt, giltiga relationer) körs. - Andra pluginers hooks körs som vid en vanlig sparning (t.ex. CMS:ets slug och HTML-tvätt). Vid torrkörning och fel rullas databasändringarna tillbaka, men en hook som gör något utanför databasen direkt (inte "efter lyckad sparning") kan inte ångras.
- Ändringar via import loggas inte av granskningsloggen (den loggar API-anrop, importen sparar i serverkod).
- En textcell som verkligen ska börja med
'följt av=,+,-,@eller'tappar sitt första'vid import (formelskyddets pris). Värden som bara börjar med'följt av något annat rörs inte. - En import låser databasen för skrivning medan den pågår (en transaktion).
#Testa
./bank.py import-export
13 tester: rundresa JSON och CSV (knepiga värden, svenska tecken, emoji, relationer, fleraval, JSON, geo, datum, dolda fält) ger identiska data; Pythons egen CSV-läsare läser exporten rätt; semikolon och Excel-värden (decimalkomma, ja/nej); allt eller inget (både valideringsfel och unik nyckel i databasen); torrkörning; skapa/uppsert; okända kolumner och trasig CSV/JSON; gäster och användare nekas; systemsamlingar (namn och id), loggar och vyer nekas; dolda fält och lösenord; import av användare; filfält; taken. Skydden är mutantverifierade: 25 mutanter, 24 fångade. Den som överlever är vår vy-spärr — PocketBase vägrar själv att spara i en vy, så importen blir 400 ändå.