问题
In a lambda function, I have the following code:
var user;
exports.handler = function uploadToS3(event, context, callback) {
var name = event["username"];
MongoClient.connect(uri, { useNewUrlParser: true }, (error, client) => {
if (error) return 1; // Checking the connection
db = client.db(databasename);
db.collection("user_profile").findOne({ username: name }, function(
err,
result
) {
if (err) throw err;
user = result._id;
console.log(user); // 1st console.log
});
});
console.log(user); //2nd console.log
};
In the above code, I have declared user as a global variable. In 1st console.log it will display the value but in 2nd console.log it will undefined. find the below output of lambda function.
Function Logs:
2019-08-23T15:23:34.610Z 83141f62-f840-4e52-9440-35f3be7b0dc8
5d5eaa9f921ed00001ee1c3f
2019-08-23T15:23:34.192Z 83141f62-f840-4e52-9440-35f3be7b0dc8
undefined
How can I get a value in the second case?
回答1:
The problem is not so much storing the mongodb output into a variable, as it is a synchronous vs asynchronous behavior. Javascript by design is synchronous, but has capability to handle asynchronous tasks. The method that performs the mongo query is asynchronous. Read: Javascript calls findOne(), this returns an 'pending' promise, then your script continues to call console.log(user) - which is still undefined. When the request from MongoDB comes back, javascript resolves the promise and executes any further actions and/or callbacks.
The second console.log comes back and is evaluated BEFORE the mongo client returns a response and assigns a new value to your variable. If you look at the timestamp of the responses, the undefined one comes back before the one with the value. It looks like you are using mongoose, which should return a promise and you can try putting that second call inside a .then, or a .done block. e.g:
var user;
exports.handler = function uploadToS3(event, context, callback) {
var name = event["username"];
MongoClient.connect(uri, { useNewUrlParser: true }, (error, client) => {
if (error) return 1; // Checking the connection
db = client.db(databasename);
db.collection("user_profile").findOne({ username: name }, function(
err,
result
) {
if (err) throw err;
user = result._id;
console.log(user); // 1st console.log
})
.done(function(){
console.log(user); //2nd console.log
});
});
};
If not using mongoose... make your own promise, or use a callback, or just try Mongoose (it rocks!) :)
*note that I put the .done after the findOne(), but I believe you could attach a .done() to the .connect() as well. (Don't quote me on that. You would have to test it, see when that promise resolves exactly)
Additionally, I would suggest storing this value outside of your lambda somehow. You might not get the same container bootstrapped for each lambda execution. You could have some issues with this down the line.
Check out:
- AWS Lambda caching issues with Global Variables - https://medium.com/tensult/aws-lambda-function-issues-with-global-variables-eb5785d4b876
- Improving Performance From Your Lambda Function From the Use of Global Variables - https://blog.ruanbekker.com/blog/2018/08/27/improving-performance-from-your-lambda-function-from-the-use-of-global-variables/
- AWS Lambda best practices - https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html
来源:https://stackoverflow.com/questions/57629210/how-to-store-mongodb-output-in-variable-using-nodejs-in-lambda-function