Upload csv dados alunos
[Finalizado Pelo Aluno]
Olá, Mestre!
Seguindo essa aula de upload de arquivo, qual um bom caminho para upar um csv contendo mais de 50k linhas com dados de alunos para dar uma carga inicial no novo sistema EAD?
Uma vez feito o upload, tem como, por exemplo, com algum tipo de chunk, ler o csv em pedaços de 1000 em 1000 linhas e pra cada pedaço, chamar um job passando um array com essas 1000 linhas pra ele dar insert no bd?
No Laravel tem como eu fazer esse chunk de csv?
Seria bom ter um job pra fazer esse chunk e, pra cada pedaço, chamar outro job pra processar os dados e salvar no bd?
Olá, Thiago! Como vai?
Use filas para fazer isso, com filas você pode jogar o processo inteiro para um job e deixar ele rodar, mas ainda é mais recomendado quebrar em partes e processar pedaços por pedaços.
Pra ler um arquivo com muitas linhas, eu trabalharia com php generators (isso ajuda no controle de memória).
Ou, você pode no loop mesmo de leitura do arquivo criando jobs com partes do array (10 itens por exemplo) e jogando para um job ir processando.
Pegou a ideia amigo?
Entendi a ideia.
Sobre quebrar em pedaços, seria criar vários csv menores e processar eles?
Não seria necessário, vc pode criando arrays com partes do conteúdo, e a cada loop vai zerando o array logo após enviar para o job processar.
Entendi, mestre.
A lógica principal ficou assim:
/**
* @param Request $request
* @return JsonResponse
*/
public function uploadCsv(Request $request): JsonResponse
{
// Valida o upload
$request->validate([
'csv_file' => 'required|mimes:csv|max:2048',
]);
// Armazena o arquivo CSV
$filePath = $request->file('csv_file')->store('csv_files');
$handle = fopen(storage_path('app/' . $filePath), "r");
// Lê o arquivo CSV com Generator PHP pra evitar uso excessivo de memória
$generator = $this->readCsv($handle);
// Faz Split dos dados para processá-los em grupos de N elementos
$groupSize = 1000;
$currentGroup = [];
foreach ($generator as $value) {
// Adicionar o valor atual ao grupo
$currentGroup[] = $value;
// Se o grupo atingir o tamanho desejado, processa o grupo
if (count($currentGroup) === $groupSize) {
$this->processCsv($currentGroup);
// Resetar o array de grupo
$currentGroup = [];
}
}
// Se restarem elementos no array, adicionar sozinhos
if (count($currentGroup) > 0) {
$this->processCsv($currentGroup);
}
return response()->json(['message' => 'CSV processado com sucesso.']);
}
/**
* @param $handle
* @param string $delimeter
* @return false|Generator
*/
function readCsv($handle, string $delimeter = ','): false|Generator
{
$header = [];
$row = 0;
if ($handle === false) {
return false;
}
while (($data = fgetcsv($handle, 0, $delimeter)) !== false) {
if ($row == 0) {
$header = $data;
} else {
# on demand usage
yield $data;
}
$row++;
}
fclose($handle);
}
private function processCsv(array $data)
{
// Disparar um Job pra salvar os dados no bd
}
A ideia agora é organizar esses métodos em Jobs.
O primeiro Job seria pra ler o csv upado e fazer o split, onde pra cada grupo de dados chamar um segundo job pra processá-los.
Faz sentido?
Sim, faz sentido, porque assim vc joga essa lógica para o JOB que faz o split dos dados.
Precisa estar logado para conseguir responder a este ticket!
Clique Aqui Para Entrar!