PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Modellazione di oggetti di grandi dimensioni di PostgreSQL in Rails

Se si utilizza ActiveRecord fornito con Rails con uno dei suoi adattatori, l'unica mappatura formale del tipo di database al tipo Rails o Ruby che si verifica è in genere definita in NATIVE_DATABASE_TYPES costante nell'adattatore che viene restituito tramite i suoi native_database_types metodo. Per PostgreSQL in Rails 3.2.x, cioè in ActiveRecord::ConnectionAdapters::PostgreSQLAdapter che è qui . Quindi, per quell'adattatore, il tipo "binary" in Rails viene mappato al tipo "bytea" in PG. Per alcuni tipi, puoi sovrascrivere quel tipo di database a cui è mappato usando una gem chiamata activerecord-native_db_types_override . Ma vogliamo usare oggetti di grandi dimensioni, quindi...

Migrazioni

Come ha notato Jim Deville nei commenti, puoi specificare la colonna digitata personalizzata nella tabella come:

t.column :some_oid, 'blob_oid', :null => false

Se hai bisogno di fare ancora di più che non sono standard, puoi anche usare un execute("SQL GOES HERE;") per creare la tabella utilizzando SQL diretto. E, se disponi di uno schema legacy esistente o di modifiche SQL apportate al di fuori delle migrazioni, considera l'utilizzo di structure.sql (config.active_record.schema_format = :sql opzione in config/application.rb e poi fai:rake db:structure:dump ).

Leggi/Scrivi/Controlla lunghezza/Elimina oggetti di grandi dimensioni

Copiato con alcune modifiche per chiarire, ecc. da:https://github.com/diogob/carrierwave-postgresql/blob/v0.1.0/lib/carrierwave/storage/postgresql_lo.rb :

Aggiornato :possiamo, ma non è necessario, iniziare prima di lo_read/lo_write/lo_lseek e fare lo_close nel blocco garantire perché per Documentazione PG "Tutti i descrittori di oggetti di grandi dimensioni che rimangono aperti alla fine di una transazione verranno chiusi automaticamente." (grazie a Diogo per le informazioni)

    require 'pg'

    ...

    def read
      (...).transaction do
        lo = connection.lo_open(identifier)
        content = connection.lo_read(lo, file_length)
        connection.lo_close(lo)
        content
      end
    end

    def write(file)
      (...).transaction do
        lo = connection.lo_open(identifier, ::PG::INV_WRITE)
        size = connection.lo_write(lo, file.read)
        connection.lo_close(lo)
        size
      end
    end

    def delete
      connection.lo_unlink(identifier)
    end

    def file_length
      (...).transaction do
        lo = connection.lo_open(identifier)
        size = connection.lo_lseek(lo, 0, 2)
        connection.lo_close(lo)
        size
      end
    end

Invece di connection , utilizzare la connessione grezza del modello o della base, ad es. ActiveRecord::Base.connection.raw_connection (vedi questo ).

(...).transaction chiama la transazione sul modello o sulla base, ad es. ActiveRecord::Base.transaction (vedi questo ).

identifier è l'oid che devi passare/impostare o ottenere semplicemente facendo un connection.lo_creat .

Altri esempi/informazioni:

Quest'ultimo e alcune risposte qui suggerisci di considerare l'archiviazione di file di grandi dimensioni separata dal DB, ad es. in modo da poter utilizzare il cloud storage. Ma, se solo archivia i percorsi/ID di file esterni che non gestiti dal DB, si perde la coerenza ACID (uno o più record DB potrebbero puntare a uno o più file che non ci sono oppure potrebbero esistere uno o più file che non hanno uno o più record associati nel database). Un altro argomento per l'archiviazione di file nel file system è che è possibile eseguire lo streaming di file, ma l'oggetto di grandi dimensioni PG archivia i file nel file system in un modo gestito da postgres per garantire la coerenza ACID e consentire lo streaming (cosa che non è possibile fare con un normale BLOB /Tipo binario di binari). Quindi, dipende solo; alcuni ritengono che l'archiviazione in una memoria separata utilizzando i riferimenti di percorso sia un'opzione migliore e alcuni preferiscono la coerenza ACID tramite oggetti di grandi dimensioni.

Il modo più semplice

Basta usare CarrierWave e carrierwave-postgresql .