Executando verificação de segurança...
1

Inserindo muitas linhas no banco de dados (NODE.JS)

Olá,

Atualmente tenho um projeto com Baileys (integração com WhatsApp), onde possui um evento que retorna todos os contatos salvos no celular.

Nesse retorno dos contatos, preciso armazenar ele no banco de dados, porém como são 1000+ contatos (é um SaaS então varia a quantia pela empresa) preciso de uma maneira de inserir isso sem interferir no restante das iterações (fazer algo pra salvar em background talvez?).

Framework utilizado: Adonis.JS

const upsert: BaileysEventHandler<'contacts.upsert'> = async (contacts: BaileysContact[]) => {
		try {
			const trx = await Database.transaction();
			
			const transformedContacts = await Promise.all(
				contacts.map(async (data) => {
					return transformDataOnStore(data);
				})
			);

			const wppIds = transformedContacts.map((contact) => contact.wpp_id);
			const images = await contactService.getMultipleImages(wppIds, client);

			if (images?.length) {
				transformedContacts.forEach((contact, index) => {
					const matchedImage = images.find((img) => img.wpp_id === contact.wpp_id);
					transformedContacts[index]['img_url'] = matchedImage?.image ?? null;
				});
			}

			await Contact.updateOrCreateMany('wpp_id', transformedContacts, trx);
		} catch (error) {
			Logger.error(error, 'Ocorreu um erro ao criar/atualizar contatos');
		}
	};
        ``
Carregando publicação patrocinada...
2

vê se a responsta do chatgpt te ajuda:

Para lidar com a inserção de um grande número de contatos no banco de dados sem interferir no restante das operações, você pode usar uma abordagem assíncrona e/ou paralela para inserir os contatos em lotes. Aqui está um exemplo de como você pode fazer isso no Adonis.JS usando async/await e Promise.all:

const upsert: BaileysEventHandler<'contacts.upsert'> = async (contacts: BaileysContact[]) => {
    try {
        // Dividir os contatos em lotes para inserção
        const batchSize = 100; // Número de contatos em cada lote
        const batches = [];
        for (let i = 0; i < contacts.length; i += batchSize) {
            batches.push(contacts.slice(i, i + batchSize));
        }

        // Executar a inserção em lotes em paralelo
        await Promise.all(batches.map(async (batch) => {
            const trx = await Database.transaction();
            const transformedContacts = await Promise.all(batch.map(async (data) => {
                return transformDataOnStore(data);
            }));

            const wppIds = transformedContacts.map((contact) => contact.wpp_id);
            const images = await contactService.getMultipleImages(wppIds, client);

            if (images?.length) {
                transformedContacts.forEach((contact, index) => {
                    const matchedImage = images.find((img) => img.wpp_id === contact.wpp_id);
                    transformedContacts[index]['img_url'] = matchedImage?.image ?? null;
                });
            }

            await Contact.updateOrCreateMany('wpp_id', transformedContacts, trx);
            await trx.commit();
        }));
    } catch (error) {
        Logger.error(error, 'Ocorreu um erro ao criar/atualizar contatos');
    }
};

Neste código, os contatos são divididos em lotes de tamanho batchSize e cada lote é inserido em uma transação separada. Isso permite que as inserções ocorram em paralelo, melhorando a eficiência e reduzindo o tempo total de processamento. Certifique-se de ajustar o tamanho do lote conforme necessário com base na capacidade do seu banco de dados e nos requisitos de desempenho.

E também tem isso aqui

Aqui estão cinco formas de lidar com o caso de inserir muitas linhas no banco de dados em Node.js, considerando a necessidade de inserir os contatos em background sem interferir no restante das iterações:

  1. Utilizando Filas de Tarefas (ex: Bull):

    • Crie uma fila de tarefas utilizando uma biblioteca como Bull.
    • Adicione os contatos à fila para serem processados em background.
    • Implemente um worker que irá processar os contatos da fila e inseri-los no banco de dados.
    • Isso permite que a inserção seja feita de forma assíncrona e em background, sem interferir nas outras operações.
  2. Utilizando Promessas e Assincronia:

    • Envie a inserção dos contatos para uma função assíncrona que será executada em segundo plano.
    • Isso pode ser feito utilizando setTimeout com um tempo curto para garantir que a função seja executada em background.
  3. Dividindo em Lotes (Batching):

    • Divida os contatos em lotes menores e insira cada lote separadamente.
    • Isso evita sobrecarregar o banco de dados com um grande número de inserções de uma vez.
    • Utilize uma estratégia de controle de taxa para garantir que os lotes sejam inseridos de forma eficiente.
  4. Utilizando Threads de Trabalho (Worker Threads):

    • Utilize threads de trabalho para realizar a inserção dos contatos em paralelo.
    • Isso permite que a inserção seja feita de forma concorrente, aproveitando melhor os recursos do sistema.
  5. Utilizando Processos Secundários (Child Processes):

    • Crie processos secundários para lidar com a inserção dos contatos.
    • Isso permite que a inserção seja feita em um processo separado, deixando o processo principal livre para outras operações.

Escolha a abordagem que melhor se adapta às necessidades do seu projeto e à infraestrutura disponível.

1

Acabei vendo que no adonis tem algo pré pronto (Knex) pra fazer inserções particionadas, que seria o batchInsert. Ficou ligeiramente mais eficaz, porém não sei se atingi a melhor prática ainda, sabendo que é um SaaS, então serão muitas empresas salvando os contatos (embora seja apenas uma vez ao ler o QRCode).

Agradeço a ajuda <3