2011-10-18 4 views
7

Ho un'applicazione Rails 3 in cui ho bisogno di importare un file XML fornito da un sistema esterno in un database Postgres. Vorrei utilizzare qualcosa come ActiveRecord-Import ma questo non sembra gestire le funzionalità di upsert per Postgres, e alcuni dei record che inserirò saranno già esistenti, ma dovranno essere aggiornati.Bulk upsert con Ruby on Rails

La maggior parte di ciò che sto leggendo consiglia di scrivere SQL al volo, ma questo sembra un problema che potrebbe essere già stato risolto. Non riesco a trovarlo.

Grazie.

+0

Non sono sicuro che Rails sia lo strumento giusto per questo. Hai considerato di farlo al di fuori di Rails utilizzando gli strumenti XML e PostgreSQL esistenti? –

+0

Una volta nel database, i dati inseriti diventano modelli usati per altri scopi, modificabili attraverso il web ecc. Abbiamo convalide e associazioni sul modello. Sono preoccupato che l'interruzione dei binari ci porterà a duplicare molto lavoro e rendere difficile la manutenzione lungo la strada. –

+3

Se si desidera eseguire le convalide di ActiveRecord, sarà necessario inserire un record alla volta. Se si desidera eseguire l'aggiornamento cumulativo + le convalide, sarà necessario impostare convalide/vincoli sul lato db. Se si desidera l'efficienza in questo caso, potrebbe essere necessario scendere a compromessi sulla manutenibilità del codice –

risposta

-1

È una cosa in due fasi. Per prima cosa devi recuperare il file XML. Se è fornito da un utente tramite un modulo che fortuna per te altrimenti è necessario recuperarlo utilizzando la lib di HTTP standard rubino o altrimenti qualche gioiello come meccanizza (che in realtà è davvero grande)

La seconda cosa è davvero facile. Hai letto tutto il codice XML in una stringa e quindi è possibile convertirlo in un hash con questa pice di codice:

Hash.from_xml(xml_string) 

Poi si può analizzare e utilizzare i dati ...

+0

Stiamo utilizzando happymapper per analizzare l'XML e funziona perfettamente. Ciò che rende difficile questo è il numero di oggetti che vogliamo importare rende molto lento se inseriamo/aggiorniamo ogni oggetto uno per uno. –

7

Si può fare upserting su MySQL e PostgreSQL con upsert.

Se stai cercando la velocità non elaborata, è possibile utilizzare nokogiri e upsert.

Potrebbe essere più semplice importare i dati utilizzando data_miner, che utilizza nokogiri e upsert internamente.

+0

Vorrei aver visto questa risposta prima – sheerun

1

Se si utilizza PostgreSQL 9.1, è necessario utilizzare espressioni di tabella comuni scrivibili. Qualcosa di simile:

WITH updates (id) AS (
    UPDATE mytable SET ..... 
     WHERE .... 
    RETURNING id 
) 
INSERT INTO mytable (....) 
SELECT ... 
    FROM mytemptable 
WHERE id NOT IN (select id from updates); 

In questo caso è processo in massa si assottiglia in una tabella temporanea, poi si cercherà di aggiornare i record dalla TempTable secondo la tua logica, e inserire il resto.