11const fs = require ( 'fs' ) ;
2+ const util = require ( 'util' ) ;
3+ const readline = require ( 'node:readline' ) ;
4+
25const papa = require ( 'papaparse' ) ;
36const 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"
710const credentials = new AWS . SharedIniFileCredentials ( { profile : 'default' } ) ;
811AWS . config . update ( { region : 'us-east-2' , credentials } ) ;
912
13+ // * Inicializamos el servicio de DynamoDB
1014const 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