Warum ist der Export wichtig? Paperless läuft doch!
Ja das stimmt, aber den Export brauchst Du
- Evt. wenn Du von Paperless weg möchtest und die Dokumente mitnehmen
- Evt. als individuelles Backup
- Evt. beim Wechsel in Paperless zu anderen Datenbanken
- Evt. beim Major Versions Upgrade von Paperless selbst
Meine Ausgangssituation:
- Anfangs hatte ich von Docker und Bash Null Ahnung, jetzt zumindest kein blutiger Anfänger mehr
- Paperless Docker auf Synology NAS mit Container Manager installiert
- 7200 Dokumente enthalten (größtenteils gescannt aber auch frühere PDF mit tlw langen Dateinamen)
- Backup: In compose.yaml fast nur feste Versionen verdrahtet und mit Hyperbackup Versionsrotation. Zusätzlich über Aufgabenmanager/Bash Script ein regelmäßiger Postgres DB Dump)
Wichtig: Bevor Ihr etwas ausprobiert, immer ein Backup machen!
Hier das Script, mit dem ich den Dump und/oder den Dokumenten Export anstoße.
Zusammenfassung
#!/bin/bash
# === Konfiguration ===
DOKUMENTENEXPORT="2" # 1 = true
PROJECT_DIR="/volume1/docker/paperless-office"
DOKUMENTE_EXPORT_DIR="$PROJECT_DIR/export"
DB_CONTAINER="paperless-office-postgres"
DB_USER="xxx"
DB_NAME="xxx"
DB_VOLUME_PATH="/var/lib/postgresql/data"
DB_DUMP_FILENAME="backup_dbdump.sql"
DB_DUMP_PATH="$DB_VOLUME_PATH/$DB_DUMP_FILENAME"
# === Export-Verzeichnis prüfen und leeren ===
if [ -n "$DOKUMENTE_EXPORT_DIR" ] && [ -d "$DOKUMENTE_EXPORT_DIR" ]; then
echo "[INFO] Leere Dokumenten-Export-Verzeichnis: $DOKUMENTE_EXPORT_DIR"
rm -rf "$DOKUMENTE_EXPORT_DIR"/*
else
echo "[ERROR] Dokumenten-Export-Verzeichnis existiert nicht. Abbruch."
exit 1
fi
# === In Projektverzeichnis wechseln ===
cd "$PROJECT_DIR" || { echo "[ERROR] Projektverzeichnis nicht gefunden: $PROJECT_DIR"; exit 1; }
# === PostgreSQL Dump erstellen ===
# Erst der DB Dump weil wenn zu lange Namen, bricht das Script ab ohne den DB Dump zu machen
echo "[INFO] Erstelle PostgreSQL-Dump: $DB_DUMP_PATH"
docker exec "$DB_CONTAINER" pg_dump -U "$DB_USER" -d "$DB_NAME" -F p -f "$DB_DUMP_PATH"
if [ $? -eq 0 ]; then
echo "[OK] Datenbank-Dump erfolgreich gespeichert unter: $PROJECT_DIR/postgres/$DB_DUMP_FILENAME"
else
echo "[ERROR] Fehler beim Datenbank-Dump!"
exit 1
fi
# === Dokumente exportieren ===
if [ "$DOKUMENTENEXPORT" = "1" ]; then
echo "[INFO] Starte Dokumenten-Export..."
if docker-compose exec -T webserver document_exporter ../export; then
echo "[OK] Dokumenten-Export erfolgreich abgeschlossen."
else
echo "[WARNUNG] Dokumenten-Export fehlgeschlagen – wird ignoriert."
echo "[WARN] Fehler beim Export am $(date)" >> "$PROJECT_DIR/backup.log"
fi
fi
Welche Probleme traten beim Export der Dokumente auf?
- Script brach brach Mitten im Export ab mit Exception ab “OSError: [Errno 36] File name too long:”
Zusammenfassung
Traceback (most recent call last):
File "/usr/src/paperless/src/manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.12/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.12/site-packages/django/core/management/__init__.py", line 436, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.12/site-packages/django/core/management/base.py", line 413, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/local/lib/python3.12/site-packages/django/core/management/base.py", line 459, in execute
output = self.handle(*args, **options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/paperless/src/documents/management/commands/document_exporter.py", line 233, in handle
self.dump()
File "/usr/src/paperless/src/documents/management/commands/document_exporter.py", line 337, in dump
self.copy_document_files(
File "/usr/src/paperless/src/documents/management/commands/document_exporter.py", line 510, in copy_document_files
self.check_and_copy(
File "/usr/src/paperless/src/documents/management/commands/document_exporter.py", line 574, in check_and_copy
if target.exists():
^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/pathlib.py", line 860, in exists
self.stat(follow_symlinks=follow_symlinks)
File "/usr/local/lib/python3.12/pathlib.py", line 840, in stat
return os.stat(self, follow_symlinks=follow_symlinks)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 36] File name too long: '/usr/src/paperless/export/2011-04-11 xxx ganz langer Name.pdf'
[WARNUNG] Dokumenten-Export fehlgeschlagen – wird ignoriert.
- Script brach Mitten im Export ab mit Exception ab “FileNotFoundError: [Errno 2] No such file or directory:”
Zusammenfassung
Traceback (most recent call last):
File "/usr/src/paperless/src/manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.12/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.12/site-packages/django/core/management/__init__.py", line 436, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.12/site-packages/django/core/management/base.py", line 413, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/local/lib/python3.12/site-packages/django/core/management/base.py", line 459, in execute
output = self.handle(*args, **options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/paperless/src/documents/management/commands/document_exporter.py", line 233, in handle
self.dump()
File "/usr/src/paperless/src/documents/management/commands/document_exporter.py", line 337, in dump
self.copy_document_files(
File "/usr/src/paperless/src/documents/management/commands/document_exporter.py", line 522, in copy_document_files
self.check_and_copy(
File "/usr/src/paperless/src/documents/management/commands/document_exporter.py", line 591, in check_and_copy
copy_file_with_basic_stats(source, target)
File "/usr/src/paperless/src/documents/utils.py", line 46, in copy_file_with_basic_stats
shutil.copy(source, dest)
File "/usr/local/lib/python3.12/shutil.py", line 435, in copy
copyfile(src, dst, follow_symlinks=follow_symlinks)
File "/usr/local/lib/python3.12/shutil.py", line 260, in copyfile
with open(src, 'rb') as fsrc:
^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/usr/src/paperless/media/documents/archive/documents/originals/0000823.pdf'
[WARNUNG] Dokumenten-Export fehlgeschlagen – wird ignoriert.
Noch eins vorweg, es gibt sicher auch noch andere Möglichkeiten, den Problemen beizukommen. Aber so habe ich es gestern bis zu einem wieder funktionierendem Export hinbekommen.
Lösung für zu lange Namen:
-
Verbinde Dich per SSH als admin und sudo -i (Vorsicht ab diesem Punkt!)
-
docker ps zeigt Dir die Namen
-
Verbinde Dich zur Datenbank: docker exec -it paperless-office-postgres psql -U DEINUSER -d DEINEPAPERLESSDB
-
Wenn Du das siehst, bist Du auf der DB
-
Kopiere das SQL in Deine SSH Session
SELECT id, title, LENGTH(title) AS title_length
FROM documents_document
WHERE LENGTH(title) > 100
ORDER BY title_length ASC;
Jetzt habe ich es mit Try-And-Error versucht und kam bei mir zu dem Schluß die Dateinamen dürfen maximal 130 Zeichen sein, damit sie mit Pfaden nachher nicht die 255 erlaubte Zeichen überschreiten und so zu obiger Exception beim Export führen. Damit ich hier etwas zeigen kann, habe ich das SQL Statement auf 100 Zeichen gesetzt. Du kannst die Zahl auch heruntersetzen, um bei Dir etwas zu sehen. Das ist ein lesender Befehl, der nichts kaputt macht.
- Danach bin ich in Paperless gegangen und habe die Dateinamen verkürzt.
Danach gab es diese Exception beim Export nicht mehr.
Lösung von verwaisten Referenzen ohne reale Dokumente
Meine Vermutung wie es dazu kommen konnte:
Beim Einscannen hatte ich ein paar gemerkt, daß Seiten zu einem Dokument gehören, ich aber den ersten Teil bereits eingescannt und nach CONSUME geschickt hatte. Da Paperless mit dem Import anderer beschäftigt war, habe ich das letzte gelöscht und dachte es geht. Aber vermutlich referenziert Paperless bereits jedes Dokument im CONSUME. Wie gesagt, ist nur eine Vermutung.
- Falls Ihr noch in voriger DB Session seid, müßt Ihr vorher mit \q wieder raus
- Ansonsten wie oben beschrieben, SSH auf Docker
- Gebe diesen Befehl ein um Python Script verwenden zu können
docker exec -it paperless-office-webserver python3 /usr/src/paperless/src/manage.py shell
- Dann kopiert Ihr diese Befehle als eines in die Konsole
import os
from documents.models import Document
missing = []
for doc in Document.objects.all():
try:
abs_path = str(doc.archive_path)
if not os.path.exists(abs_path):
missing.append((doc.id, doc.title, abs_path))
except Exception as e:
missing.append((doc.id, doc.title, f"Fehler: {e}"))
Und mit
len(missing)
fragt Ihr das Array ab.
Gestern waren es bei mir 9, heute 0
- Dann die “Dokumente” listen mit
for idx, (doc_id, title, path) in enumerate(missing, start=1): print(f"{idx}. ID: {doc_id}, Titel: {title}, Pfad/Fehler: {path}")
- Bis hierhin war alles nur lesen, jetzt kommt ein Datenbank Inhalt schreibender Befehl, also bitte Vorischt! Ihr holt Euch die ID’s der Dokumente aus Eurem Konsolen Ergebnis und setzt den Befehl zusammen
from documents.models import Document; Document.objects.filter(id__in=[816, 584, 6697, 7053, 823, 335, 2417, 1328, 615]).delete()
Es gibt ein Fehlermeldungen, deren Ursache bereits bekannt ist. Das Dokument gibt es nicht.
- Aus Python mit STRG+D herausgehen und mit EXIT SSH
Finaler Beweis eines wieder funktionierenden Exports
Obiges Backup Script angestoßen und bei > 7000 Dokumenten dauert es ein paar Minuten
Die verkürzte Log Ausgabe sieht so aus:
[INFO] Leere Dokumenten-Export-Verzeichnis: /volume1/docker/paperless-office/export
/bin/bash: line 17: /bin/rm: Argument list too long
[INFO] Erstelle PostgreSQL-Dump: /var/lib/postgresql/data/backup_dbdump.sql
[OK] Datenbank-Dump erfolgreich gespeichert unter: /volume1/docker/paperless-office/postgres/backup_dbdump.sql
[INFO] Starte Dokumenten-Export...
0%| | 0/7252 [00:00<?, ?it/s]
0%| | 4/7252 [00:00<03:28, 34.73it/s]
0%| | 14/7252 [00:00<01:45, 68.51it/s]
0%| | 24/7252 [00:00<01:28, 82.05it/s]
1%| | 48/7252 [00:00<00:50, 141.51it/s]
1%| | 67/7252 [00:00<00:45, 156.99it/s]
1%| | 83/7252 [00:00<00:45, 156.38it/s]
1%|▏ | 104/7252 [00:00<00:41, 170.88it/s]
2%|▏ | 122/7252 [00:00<00:42, 168.87it/s]
2%|▏ | 146/7252 [00:00<00:40, 174.89it/s]
2%|▏ | 172/7252 [00:01<00:35, 198.88it/s]
3%|▎ | 193/7252 [00:01<00:36, 195.10it/s]
...
90%|████████▉ | 6522/7252 [00:24<00:01, 485.20it/s]
91%|█████████ | 6580/7252 [00:24<00:01, 508.83it/s]
92%|█████████▏| 6637/7252 [00:24<00:01, 526.01it/s]
92%|█████████▏| 6695/7252 [00:24<00:01, 540.96it/s]
93%|█████████▎| 6753/7252 [00:24<00:00, 551.32it/s]
94%|█████████▍| 6811/7252 [00:24<00:00, 557.91it/s]
95%|█████████▍| 6869/7252 [00:25<00:00, 563.45it/s]
96%|█████████▌| 6927/7252 [00:25<00:00, 568.03it/s]
96%|█████████▋| 6985/7252 [00:25<00:00, 565.87it/s]
97%|█████████▋| 7042/7252 [00:25<00:00, 548.49it/s]
98%|█████████▊| 7100/7252 [00:25<00:00, 555.19it/s]
99%|█████████▊| 7158/7252 [00:25<00:00, 559.77it/s]
99%|█████████▉| 7215/7252 [00:26<00:00, 180.49it/s]
100%|██████████| 7252/7252 [00:28<00:00, 256.72it/s]
[OK] Dokumenten-Export erfolgreich abgeschlossen.
Vola, geht wieder, puuhh.