Am ly
Am ly

Reputation: 7

Why my code doesn't put anything in my table?

I tried to import data from a csv file stocked in S3, and put the data in DynamaDB table. In my Lambda function which is in node.js, everything works fine, my data is well exported.

I tried to see if it was a problem with my Item, so I put the var params at the begining of the function (before the s3.getObjet) and the data was put in my dynamoDB table. Also, I tried to see if my problem was my if, but no console.log works fine in the if. I think, the only problem is my code, and I think it's a scope problem ?

var AWS = require("aws-sdk"),
    documentClient = new AWS.DynamoDB.DocumentClient(); 
var s3 = new AWS.S3();

exports.handler = function(event, context, callback) {
    var src_bkt = event.Records[0].s3.bucket.name;
    var src_key = event.Records[0].s3.object.key;
    var file;
    var lignea;

    // Retrieve the object
    s3.getObject({
        Bucket: src_bkt,
        Key: src_key
    }, function(err, dataFile) {
        if (err) {
            console.log(err, err.stack);
            callback(err);
        } else {
            file = dataFile.Body.toString('ascii');
            var rows = file.split('\n');
            for(var i in rows){
                lignea = rows[i].split(';');
                if(lignea[2].startsWith('/France/Toulouse/')){
                    console.log("hey");
                    var params = {
                        Item : {
                            "ASSETTAG" : 'c',
                            "MAINHOST" : 'c'
                        },
                            TableName : process.env.TABLE_NAME
                        };
                        documentClient.put(params, function(err, data){
                            callback(err, data);
                    });
                }
            }
        }
    });
};

Edit : With help, my async code is like this :

var AWS = require("aws-sdk"),
    documentClient = new AWS.DynamoDB.DocumentClient(); 
var s3 = new AWS.S3();

exports.handler = async function(event, context, callback) {
    var src_bkt = event.Records[0].s3.bucket.name;
    var src_key = event.Records[0].s3.object.key;
    var file;
    var lignea;
    try{
    // Retrieve the object
    const dataFile = s3.getObject({
        Bucket: src_bkt,
        Key: src_key
    }).promise();

    file = dataFile.Body.toString('ascii');
    var rows = file.split('\n');
        for(var i in rows){
        lignea = rows[i].split(';');
                if(lignea[2].startsWith('/France/Toulouse/')){
            console.log("hey");
            var params = {
                Item : {
                    "ASSETTAG" : 'test1',
                    "MAINHOST" : 'test2'
                },
                    TableName : process.env.TABLE_NAME
                };
                await documentClient.put(params).promise();  
        }
    }
    }catch(e){
        console.error("FAIL");
    }
};

Thank you for your help !

Upvotes: 0

Views: 637

Answers (3)

jcragun
jcragun

Reputation: 2198

You're right, it's a scope problem because you're calling an async function within a for loop. You could rewrite it like this, I believe:

function putDocument (params) {
    return function() { documentClient.put(params, callback) };
}

for(var i in rows){
    lignea = rows[i].split(';');
    if(lignea[2].startsWith('/France/Toulouse/')){
        console.log("hey");
        var params = {
            Item : {
                "ASSETTAG" : 'c',
                "MAINHOST" : 'c'
            },
            TableName : process.env.TABLE_NAME
        };
        putDocument(params);
    }
}

You could also try using let when defining params as it'll have the correct scope or use .forEach to create a closure.

Upvotes: 0

Adrian Praja
Adrian Praja

Reputation: 412

Two things I noticed

  • you are calling callback in a loop, for each row for each line
  • you are calling put with the same params

you should use a package like "async"

var AWS = require("aws-sdk"),
	documentClient = new AWS.DynamoDB.DocumentClient(); 
var s3 = new AWS.S3();
var async = require("async")

exports.handler = function(event, context, callback) {
	var src_bkt = event.Records[0].s3.bucket.name;
	var src_key = event.Records[0].s3.object.key;
	var file;
	var lignea;
	
	// Retrieve the object
	s3.getObject({
		Bucket: src_bkt,
		Key: src_key
	}, function(err, dataFile) {
		if (err) {
			console.log(err, err.stack);
			return callback(err);
		} 

		var things_to_insert = []

		file = dataFile.Body.toString('ascii');
		var rows = file.split('\n');
		for(var i in rows){
			lignea = rows[i].split(';');
			if(lignea[2].startsWith('/France/Toulouse/')){
				console.log("hey");
				var params = {
					Item : {
						"ASSETTAG" : lignea[0], // this must be your partition key
						"MAINHOST" : lignea[1]  // this must be your sort key
					},
					TableName : process.env.TABLE_NAME
				};
				things_to_insert.push(params)
			}
		}

		async.forEachOf(things_to_insert, function(params, key, cb ) {
			documentClient.put(params, function(err, data){
				cb(err, data);
			});
		}, function(err) {
			callback(err) // called only once at the end 
		})
	});
};

Upvotes: 0

ttulka
ttulka

Reputation: 10882

You're actually calling handler's callback when a first put result comes, which results to the immediate end of process.

Try these changes:

exports.handler = async function

This enables async/await mechanism of dealing with async code.

await documentClient.put(params).promise();

Almost all AWS methods have this variant returning a Promise instead of using a callback. await syntax wait for a Promise result in synchronous manner.

const dataFile = await s3.getObject({
        Bucket: src_bkt,
        Key: src_key
    }).promise();

Remove callbacks whatsoever.

Close the whole handler into a try/catch block.

Upvotes: 1

Related Questions