Bulk Import Deduplication System
This document explains how OpenRegister handles duplicate prevention during bulk CSV imports and provides technical details about the implementation.
Overview
OpenRegister's bulk import system uses advanced database-level deduplication to prevent duplicate objects during CSV imports, even when the same file is imported multiple times. This system maintains high performance (sub-1-second imports for 1000+ objects) while ensuring data integrity.
How It Works
Revolutionary Single-Call Architecture
The deduplication system uses a single database operation with timestamp-based classification to eliminate the need for pre-lookup queries while providing exact per-object create/update tracking.
Core Components
-
UNIQUE Constraint: Prevents duplicates at database level
-- Applied via Migration Version1Date20250908174500
ALTER TABLE oc_openregister_objects ADD CONSTRAINT unique_uuid UNIQUE (uuid); -
Smart Timestamp Handling: Enables precise classification
-- Applied via Migration Version1Date20250908180000
created DATETIME DEFAULT CURRENT_TIMESTAMP, -- Set only on INSERT
updated DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -- Set on INSERT + UPDATE
Revolutionary Import Flow
- CSV Processing: Objects parsed and UUIDs assigned
- Single Bulk Operation: All objects processed in one call:
INSERT INTO oc_openregister_objects (uuid, name, created, updated, ...) VALUES
('uuid1', 'value1', NOW(), NOW(), ...),
('uuid2', 'value2', NOW(), NOW(), ...)
ON DUPLICATE KEY UPDATE
name = VALUES(name),
updated = NOW(), -- Only updated changes, created stays original
... - Complete Object Retrieval: Query back all processed objects:
SELECT * FROM oc_openregister_objects WHERE uuid IN ('uuid1', 'uuid2', ...); - Timestamp Classification:
- created = updated: Object was just created (INSERT)
- created ≠ updated: Object was updated (ON DUPLICATE KEY UPDATE)
- created < updated: Object had actual changes and was modified
Revolutionary Benefits
- Eliminated Pre-Lookup: No need to query existing objects first
- Single Database Call: Maximum efficiency with one bulk operation
- Exact Per-Object Tracking: Precise create/update/unchanged statistics
- Intelligent Updates: Only objects with changes get updated timestamps
- Zero Duplicates: Guaranteed by database constraints
- Superior Performance: Even faster than the previous approach
Technical Implementation
Migration Setup
The system requires a UNIQUE constraint on the UUID field, applied via Nextcloud migration:
// lib/Migration/Version1Date20250908174500.php
class Version1Date20250908174500 extends SimpleMigrationStep
{
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper
{
$schema = $schemaClosure();
if ($schema->hasTable('openregister_objects')) {
$table = $schema->getTable('openregister_objects');
if ($table->hasColumn('uuid') && !$table->hasIndex('unique_uuid')) {
$table->addUniqueIndex(['uuid'], 'unique_uuid');
$output->info('