En ocaciones se nos presenta el caso donde tenemos que importar un archivo csv y almacenar los registros en la base de datos, normalmente lo que se hace es leer el archivo e ir insertando uno a uno los registros pero este proceso se vuelve lento y tardado cuando la cantidad de registros a insertar es demasiado grande por ejemplo unos 10,000 items.
El proceso que mostraré fue probado con un archivo de 500,000 registros y con un tiempo de ejecución de ~8s, este tiempo puede variar en dependencia del entorno en donde se este ejecutando el código.
Les comparto el gist del archivo utilizado para las pruebas: ver en GitHub
style="display:block; text-align:center;" data-ad-format="fluid" data-ad-layout="in-article" data-ad-client="ca-pub-2384244548418509" data-ad-slot="5598091403">
Creacion de nuestra tabla
Para crear la tabla utilizaremos el proceso de migraciones
php artisan make:migration create_imports_table
public function up()
{
Schema::create('imports', function (Blueprint $table) {
$table->increments('id');
$table->string('email');
$table->string('fname');
$table->string('lname');
$table->string('address');
$table->string('city');
$table->string('state');
$table->string('zip');
$table->string('phone');
$table->ipAddress('ip');
$table->string('datetime');
$table->string('source');
$table->string('gender')->nullable();
$table->string('birth')->nullable();
$table->boolean('deliveryverified')->default(false);
$table->string('verify_date');
$table->string('smtpresponse');
$table->timestamps();
});
}
Creación del archivo Job para la importación
Un Job en laravel es un servicio que esta ejecutándose en nuestro servidor y realizando diferentes acciones en este acaso se verifica que se agregue una tarea a realizar y se pasa a realizar en segundo plano, brindándonos el beneficio de que un proceso que puede tardar varios minutos en ejecutarse al usuario se le muestre una respuesta en segundos.
Para empezar a crear nuestro Job generaremos el archivo con código inicial con el comando
php artisan make:job ImportCSV
Una vez creado se procede a programar las instrucciones a realizar, nuestro archivo estara situado en la carpeta app/jobs de nuestro proyecto laravel.
Nuestro código quedaría de la siguiente forma, el secreto esta en la instrucción sql LOAD DATA LOCAL INFILE
que nos permite insertar todos los registros de nuestro csv en una sola instrucción sql.
Si necesitamos tratar los datos o realizar mayores acciones podemos crear tablas temporales para insertar los datos o simplemente utilizar IF ELSE como es el caso del ejemplo.
Para mas información de la configuración y ejecución de los QUEUE puedes revisar la documentación oficial en https://laravel.com/docs/5.4/queues para que realicen la configuración que mejor se adapte a lo que necesitan.
Subida del archivo
Procedemos a crear la ruta donde recibiremos el archivo, para este ejemplo decide hacerlo directo en la función callback y no en un controlador.
Route::post('/', function (){
/*
Invocando al JOB de importación.
Se le pasa la ruta del archivo que se almaceno
*/
dispatch(
new \App\Jobs\ImportCsv(
request()->file('file')->path()
)
);
return response()->json([
"success" => true
]);
});
Ustedes pueden realizar diferentes validaciones el cual decidí no colocar ya que no es el propósito del articulo.
Conclusión
Mediante este método el proceso de inserción es ejecutado con mejor eficiencia en tiempo a diferencia de haber realizado el proceso de inserción leyendo el archivo e ir insertando uno a uno que lo mas seguro que para archivos grandes muestre un timeout y no logres realizar la importación con éxito.
*Importante
Para que puedan subir archivos de gran tamaño recuerden que tiene que cambiar la configuracion de su servidor web ya sea Nginx o Apache y modificar los parametros
upload_max_filesize
ypost_max_size
del archivo php.ini si utilizan Nginx tambien hay que modificar el valor de la variableclient_max_body_size
.