Skip to content

Commit 6d34358

Browse files
committed
feat: update package name to script-dynamodb and bump version to 2.0.0
1 parent 20db169 commit 6d34358

6 files changed

Lines changed: 696 additions & 67 deletions

File tree

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
/node_modules
1+
/node_modules
2+
/csv/*.csv
3+
/logs/*.log
4+
*.pkg
5+
*.zip
6+
.DS_Store

csv/.gitkeep

Whitespace-only changes.

logs/.gitkeep

Whitespace-only changes.

main.js

Lines changed: 179 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,80 @@
11
const fs = require('fs');
2+
const util = require('util');
3+
const readline = require('node:readline');
4+
25
const papa = require('papaparse');
36
const AWS = require('aws-sdk');
4-
const file = fs.createReadStream('.csv');
7+
const file = fs.createReadStream('csv/{file-name}.csv');
58

6-
// * Usar perfil de configuracion, por defecto se usa "default"
9+
// * Usar perfil de configuración, por defecto se usa "default"
710
const credentials = new AWS.SharedIniFileCredentials({ profile: 'default' });
811
AWS.config.update({ region: 'us-east-2', credentials });
912

13+
// * Inicializamos el servicio de DynamoDB
1014
const ddb = new AWS.DynamoDB({ apiVersion: '2012-08-10' });
1115

12-
const TableName = "";
16+
// * Nombre de la tabla en DynamoDB
17+
const tableName = "{table-name}";
1318

14-
// * Parsea csv a json
15-
papa.parse(file, {
16-
header: true,
17-
skipEmptyLines: true,
18-
complete: onComplete
19-
});
19+
// * Verifica si hay duplicados en la data
20+
const checkDuplicates = (data) => {
21+
let setCheck = new Set();
22+
let set = new Set();
23+
24+
for (let i = 0; i < data.length; i++) {
25+
if (setCheck.has(data[i].InternalID)) {
26+
console.log('============================================================');
27+
28+
console.log(`=== Duplicado en la posición ${i} del arreglo ===`, data[i]);
29+
30+
console.log('============================================================\n');
31+
} else {
32+
setCheck.add(data[i].InternalID);
33+
set.add(data[i]);
34+
}
35+
}
36+
37+
38+
console.log('=== Tamaño original del arreglo ===', data.length);
39+
console.log('=== Tamaño del arreglo ya limpiado ===', setCheck.size);
40+
console.log('=== Numero de duplicados ===', data.length - setCheck.size);
41+
42+
return [...set];
43+
}
44+
45+
// * Parte el array en chunks de tamaño especificado
46+
const chunkArray = (arr, size) => {
47+
return Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => arr.slice(i * size, i * size + size));
48+
}
49+
50+
// * Convierte en promesa la escritura en DynamoDB
51+
const write2Dynamo = (params) => {
52+
return new Promise((resolve, reject) => {
53+
ddb.batchWriteItem(params, function (err, data) {
54+
if (err) {
55+
console.log("=== Error al guardar en DynamoDB ===", err);
56+
return reject(err);
57+
} else {
58+
console.log("=== Guardado en DynamoDB ===", data);
59+
return resolve(data);
60+
}
61+
});
62+
});
63+
}
64+
65+
// * Procesa la data del csv
66+
const processData = async (results, save) => {
67+
// * Verificamos si hay duplicados en el arreglo
68+
const array = checkDuplicates(results.data);
2069

21-
async function onComplete(results) {
22-
const array = results.data;
2370
const dynamoItems = array.map(item => {
2471
/*
2572
* Necesitamos obtener los valores y llaves de cada item,
26-
* para luego identifar el tipo de dato del valor y crear el objeto
73+
* para luego identificar el tipo de dato del valor y crear el objeto
2774
* con el schema de Dynamo: { PutRequest: { Item: dynamoSchema } }
2875
*/
2976
let dynamoSchema = Object.entries(item).reduce((acc, [key, value]) => {
30-
let type = isNaN(value) ? 'S' : 'N';
77+
let type = '';//isNaN(value) ? 'S' : 'N';
3178

3279
let cleanKey = key.replace(/\s/g, '');
3380

@@ -37,44 +84,145 @@ async function onComplete(results) {
3784
}
3885
})
3986
}, {});
87+
4088
return { PutRequest: { Item: dynamoSchema } }
4189
});
4290

4391
const chunks = chunkArray(dynamoItems, 25);
4492

45-
console.log('=== chunks size ===', chunks.length);
93+
let registers = 0;
94+
let error = 0;
4695

4796
for (let i = 0; i < chunks.length; i++) {
4897
try {
49-
const dynamoData = { [TableName]: chunks[i] }
50-
const params = { RequestItems: dynamoData }
51-
await write2dynamo(params)
52-
console.log('=== chunk written ===', i);
98+
console.clear();
99+
100+
console.log('\n============================================================\n');
101+
102+
console.log('=== Numero de items ===', dynamoItems.length);
103+
console.log('=== Registros guardados ===', registers += chunks[i].length);
104+
console.log('=== Tamaño del chunk ===', chunks[i].length);
105+
console.log('=== Chunks guardados ===', `${i + 1} / ${chunks.length}`);
106+
console.log('=== Errores de chunk ===', error);
107+
108+
for (let j = 0; j < chunks[i].length; j++) {
109+
console.log(`\n=== Información del chunk ${i + 1} ===`);
110+
111+
console.log(`=== Numero de item en el chunk: ${j + 1} ===`);
112+
console.log(`=== Total de keys del item: ${Object.keys(chunks[i][j]?.PutRequest.Item).length} ===`);
113+
console.log(`=== ${Object.keys(chunks[i][j]?.PutRequest.Item)} ===`);
114+
115+
console.log('\n=== Información del item ===', chunks[i][j]?.PutRequest.Item);
116+
}
117+
118+
console.log('\n============================================================\n');
119+
120+
if (save) {
121+
await write2Dynamo({
122+
RequestItems: {
123+
[tableName]: chunks[i]
124+
}
125+
});
126+
}
53127
} catch (error) {
54-
console.log("Error: ", error)
128+
console.log('\n============================================================\n');
129+
130+
console.log(`Error en el chunk ${i + 1}:`, error);
131+
error++;
132+
55133
// * Ciclamos la información del chunk
56134
for (let j = 0; j < chunks[j].length; j++) {
57135
console.log(chunks[i][j]?.PutRequest);
58136
}
137+
138+
console.log('\n============================================================\n');
139+
140+
return;
59141
}
60142
}
143+
144+
console.log('=== Finalizando proceso y guardado de logs ===');
61145
}
62146

63-
// * Parte el array en chunks de tamaño 'size'
64-
function chunkArray(arr, size) {
65-
return Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => arr.slice(i * size, i * size + size));
147+
// * Pregunta si se desea guardar en DynamoDB
148+
const question = (results) => {
149+
const rl = readline.createInterface({
150+
input: process.stdin,
151+
output: process.stdout,
152+
});
153+
154+
rl.question(`¿Desea 1)guardar los registros en DynamoDB o solo 2)generar el log? (1/2): `, async (answer) => {
155+
const save = answer.toLowerCase();
156+
157+
if (save !== '1' && save !== '2') {
158+
console.log('=== Opción no válida, finalizando proceso ===');
159+
return rl.close();
160+
}
161+
162+
await processData(results, save === '1');
163+
164+
return rl.close();
165+
});
66166
}
67167

68-
// * Promisifica la escritura en DynamoDB
69-
function write2dynamo(params) {
168+
// * Inicializa el log
169+
const initLog = () => {
70170
return new Promise((resolve, reject) => {
71-
ddb.batchWriteItem(params, function (err, data) {
72-
if (err) {
73-
return reject(err);
74-
} else {
75-
console.log("Success", data);
76-
return resolve(data);
171+
try {
172+
// * Verifica si existe la carpeta logs
173+
if (!fs.existsSync(__dirname + '/logs')) {
174+
fs.mkdirSync(__dirname + '/logs');
77175
}
78-
});
176+
177+
// * Crea el archivo de log
178+
const log_file = fs.createWriteStream(__dirname + `/logs/${new Date().getTime()}.log`, { flags: 'w' });
179+
const log_stdout = process.stdout;
180+
181+
// * Sobre escribimos la función console.log
182+
console.log = (d, ...args) => {
183+
log_file.write(util.format(d, ...args) + '\n');
184+
log_stdout.write(util.format(d, ...args) + '\n');
185+
};
186+
187+
console.log('=== Iniciando proceso y guardado de logs ===\n');
188+
189+
return resolve();
190+
} catch (error) {
191+
return reject(error);
192+
}
79193
});
80194
}
195+
196+
// * Obtener los registros que contengan un valor semejante a un string en el campo Description
197+
/*const scanData = async (value) => {
198+
const params = {
199+
TableName: tableName,
200+
FilterExpression: 'contains(Description, :value)',
201+
ExpressionAttributeValues: {
202+
':value': { S: value }
203+
}
204+
};
205+
206+
const data = await ddb.scan(params).promise();
207+
208+
return data;
209+
}
210+
211+
scanData('{value-to-scan}').then((data) => {
212+
console.log('=== Data escaneada ===', data.Items.length);
213+
}).catch((error) => {
214+
console.log('=== Error al escanear la data ===', error);
215+
});*/
216+
217+
// * Inicializamos la lectura del archivo csv y su procesamiento
218+
initLog().then(() => {
219+
// * Formateamos el archivo csv
220+
papa.parse(file, {
221+
header: true,
222+
skipEmptyLines: true,
223+
encoding: 'utf-8',
224+
complete: question
225+
});
226+
}).catch((error) => {
227+
console.log('=== Error al inicializar el log ===', error);
228+
});

0 commit comments

Comments
 (0)