I'm trying to get data outside of the getItem function off the dynamoDB, but I'm getting this error and I don't know why.
Error ValidationException: Supplied AttributeValue is empty, must contain exactly one of the supported datatypes
Here is my code
const aws = require("aws-sdk"),
docClient = new aws.DynamoDB.DocumentClient({ apiVersion: "2012-08-10" }),
ddb = new aws.DynamoDB({ apiVersion: "2012-08-10" }),
tableName = "usersDB",
exports.apiKey = async (req, res, context) => {
var params = {
TableName: tableName,
Key: {
"username": { "S": req.body.username },
},
ProjectionExpression: "apiKey"
};
chaveAPI = await ddb.getItem(params, function (err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data.Item);
}
});
};
EDIT1: Fixed the validation error but still cannot get data from dyname. Here it is fixed
exports.apiKey = async (req, res) => {
console.log("comecei")
var params = {
TableName: tableName,
Key: {
'username': {S: req.user.username}
},
ProjectionExpression: 'apiKey'
};
// Call DynamoDB to read the item from the table
dataFromDynamo = await ddb.getItem(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data.Item);
return data.Item
}
});
console.log(dataFromDynamo)
};
A few things I notice with your code sample:
You are mixing callbacks with async/await.
You aren't declaring the dataFromDynamo variable.
Instead of this
// Call DynamoDB to read the item from the table
dataFromDynamo = await ddb.getItem(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data.Item);
return data.Item
}
});
Do this
try {
// Call DynamoDB to read the item from the table
const dataFromDynamo = await ddb.getItem(params).promise()
console.log("Success", data.Item);
return data.Item
} catch (err) {
console.log("Error", err);
}
Related
In the front-end use form-data to send a post/put method to save data and edit data in the server. In the front-end have a problem with the image field. when new data is added. the new data will be saved. but when they try to edit data, the data changes made will not be saved, only saved if the image field is changed. (this problem only occurs in ios).
in IOS when they try to update data without changing the image field server will be crashed
router.put("/:id", authenticate, async (req, res) => {
uploads(req, res, function (err) {
if (err instanceof multer.MulterError) {
return send(res, RESPONSE.FILE_TOO_LARGE);
} else if (err) {
return send(res, RESPONSE.UNKNOWN_ERROR);
}
const params = {
Bucket: process.env.AWS_BUCKET_NAME,
Key: `uploads/${uuid()}`,
Body: req.file.buffer,
};
s3.upload(params, async (error, data) => {
if (error) {
send(res, RESPONSE.UNKNOWN_ERROR);
}
try {
const id = req.params.id;
const updatedData = {
first_name: req.body.first_name,
last_name: req.body.last_name,
phone: req.body.phone,
email: req.body.email,
image: data.Key,
};
const options = { new: true };
await SomeModel.findByIdAndUpdate(id.trim(), updatedData, options);
return send(res, RESPONSE.SUCCESS);
} catch (err) {
return res.status(400).send(err.message);
}
});
Sounds like you should only do the S3 upload and set image if req.file is present
router.put("/:id", authenticate, (req, res) => {
uploads(req, res, async (err) => {
if (err instanceof multer.MulterError) {
return send(res, RESPONSE.FILE_TOO_LARGE);
} else if (err) {
return send(res, RESPONSE.UNKNOWN_ERROR);
}
const id = req.params.id;
const updatedData = {
first_name: req.body.first_name,
last_name: req.body.last_name,
phone: req.body.phone,
email: req.body.email,
};
try {
if (req.file) {
const { Key } = await s3
.upload({
Bucket: process.env.AWS_BUCKET_NAME,
Key: `uploads/${uuid()}`,
Body: req.file.buffer,
})
.promise();
updatedData.image = Key;
}
await SomeModel.findByIdAndUpdate(id.trim(), updatedData, { new: true });
return send(res, RESPONSE.SUCCESS);
} catch (err) {
return res.status(400).send(err.message);
}
});
});
I try to implement a phone number verification by SMS with aws-sdk SNS and Mongoose,
But when I test it with a wrong phone number, like, some gibberish instead of real phone,
the error goes to the console, but then it won't get caught by catch and just crashes it all.
Here is my code
// requires, etc is above here
const verifyPhone = async (req, res) => {
const { phoneNumber } = req.body;
const { userId } = req.user;
let code = generateCode(6);
const session1 = await mongoose.startSession();
try {
session1.startTransaction();
const newCode = await PhoneCode.create(
[
{
userId,
code,
},
],
{ session: session1 }
);
sns.publish(
{
MessageAttributes: {
"AWS.SNS.SMS.SenderID": {
DataType: "String",
StringValue: "Testing",
},
"AWS.SNS.SMS.SMSType": {
DataType: "String",
StringValue: "Promotional",
},
},
Message: "Your code: " + code,
PhoneNumber: "65f76fguyg",
},
(err, result) => {
if (!err) {
session1.commitTransaction().then(() => {
console.log("transaction committed");
res.status(200).json({ message: "SMS sent", result });
});
} else {
console.log(err);
throw new Error(err);
}
}
);
} catch (e) {
await session1.abortTransaction();
res.status(500).json({ message: "Something went wrong!", e });
} finally {
session1.endSession();
}
};
module.exports = verifyPhone;
I suspect that the issue is in throwing the error from inside of sns.publish 's callback, but I don't understand, how else I could do that
Also, if I enter right phone number, the SMS gets delivered, I get the response, but then
mongoose crashes, saying
UnhandledPromiseRejectionWarning: MongoTransactionError: Cannot call commitTransaction after calling abortTransaction
I've just got to a solution. The solution for me was to promisify the sns.publish, after that all went like a charm.
const promisifySNS = (args) => {
return new Promise((resolve, reject) => {
sns.publish(args, (err, result) => {
if (err) {
return reject(err);
}
resolve(result);
});
});
};
Funny enough, if you use more generic promisify, for any function
const promisify = (fn, ...args) => {
return new Promise((resolve, reject) => {
fn(...args, (err, result) => {
if (err) {
return reject(err);
}
resolve(result);
});
});
};
await promisify(sns.publish, opts);
that wouldn't work for some reason.
I am trying to call some function in synchronously using node.js but as per my code its not happening. I am explaining my code below.
viewDraggedFileContent = async(req, res) => {
try{
let id = req.params.id;
if(!id) {
responseObj = {
status: 'error',
msg: 'Please send the mongo id to fetch the file content.',
body: {}
};
res.send(responseObj);
}else{
let response = await findOne(id, 'useCaseFile');
console.log('res', response);
if(response['status'] === 0) {
responseObj = {
status: 'error',
msg: `Error occurred`,
body: response['data']
};
res.send(responseObj);
}else{
const resObj = [{
fileData: response.data.fileData,
_id: response['data']['_id']
}]
responseObj = {
status: 'success',
msg: `Fetched data successfully`,
body: resObj
};
res.send(responseObj);
}
}
}catch(error) {
console.log('Error::', error);
}
}
/**
* 1- Method to fetch single record from mongoDB as per _id.
*/
findOne = async (id, collName) => {
try{
let mongoID = new ObjectId(id);
MongoClient.connect(dbUrl, dbOptions).then(function (client) {
let connObj = client.db(dbName);
connObj.collection(collName).findOne({ _id: mongoID }, function (error, doc) {
if (error) {
client.close();
return {
status: 0,
data: error
};
} else {
client.close();
return {
status: 1,
data: doc
};
}
})
})
}catch(error){
console.log('Error while fetching single record::', error);
}
}
Here I am calling findOne function from viewDraggedFileContent function. My objective is once the required data will return from findOne function then console.log('res', response); should execute but as per my code console.log('res', response); is executing before getting response from findOne. I have also used async---await but still its running asynchronously. Here I need after getting response from findOne function then the console message should display.
You can use async/await in the findOne function
async function findOne(id, collName) {
const client = await MongoClient.connect(url, {
useUnifiedTopology: true,
}).catch((err) => {
console.log("Error while connecting to db", err);
});
if (client) {
try {
let mongoID = new ObjectId(id);
let connObj = client.db(dbName);
let doc = await connObj.collection(collName).findOne({ _id: mongoID });
return {
status: 1,
data: doc,
};
} catch (error) {
console.log("Error while fetching single record::", error);
return {
status: 0,
data: error,
};
} finally {
client.close();
}
}
}
I think that your problem here is that you're not returning a promise so the line calling your findOne function doesn't await anything.
Two solutions here :
When you pass a callback to db.collection.findOne function, it doesn't return anything but, if you don't, you can await a result, like this :
const doc = await connObj.collection(collName).findOne({ _id: mongoID })
Then, you can parse your doc and return it.
The other solution if to return a promise in your findOne function and then, send your result with resolve, like this :
findOne = async (id, collName) => {
return new Promise((resolve, reject) => {
try{
let mongoID = new ObjectId(id);
MongoClient.connect(dbUrl, dbOptions).then(function (client) {
let connObj = client.db(dbName);
connObj.collection(collName).findOne({ _id: mongoID }, function (error, doc) {
if (error) {
client.close();
reject(error);
} else {
client.close();
resolve(doc);
}
})
})
}catch(error){
console.log('Error while fetching single record::', error);
}
}
}
Then, you don't anymore need a status and can use then and catch to get your result.
i need to know how i can write my request to make multiple delete.
the second thing is how can i put async function on my code.
i want to delete a campus and in the same time dele the builings with the same id campus in the JSON
app.delete('/campuses/:id', (req, res)=> {
const id = req.params.id;
const details = { 'campusid': new ObjectID(id) };
db.db('').collection('buildings').remove(details, (err, result)=> {
if (err) {
res.send({ 'error': 'en error has occured' });
} else {
res.send(result);
}
});
const details2 = { '_id': new ObjectID(id) };
db.db('').collection('campuses').remove(details2, (err, result)=> {
if (err) {
res.send({ 'error': 'en error has occured' });
} else {
res.send(result);
}
}
);
})
You can delete like this.
app.delete('/campuses/:id', async (req, res)=> {
try {
const id = req.params.id;
const details = { 'campusid': new ObjectID(id) };
await db.db('').collection('buildings').remove(details);
const details2 = { '_id': new ObjectID(id) };
await db.db('').collection('campuses').remove();
res.send(result);
} catch(err) {
return res.json({
success: false,
message: 'error'
});
}
})
You could make sequential functions where the first one calls the second one. You could then pass on variables to the seconds function (ie. your campus ID).
It could look something like this:
const Query1 = (res, query) => {
const request = new sql.Request();
request.query(query, (err, result) => {
if (err) {
return res.json({
success: false,
message: 'error'
});
} else if (result.recordset[0]) {
let campusID = result.recordset;
Query2(res, campusID, query = 'SELECT bla bla')
}
})
}
const Query2 = (res, campusID, query) => {
const request = new sql.Request();
request.query(query, (err, result) => {
if (err) {
return res.json({
success: false,
message: 'error'
});
} else {
return res.json({
success: true
});
}
})
}
There are various ways to make async call.
You can use promises.
Async Functions.
Sending response without waiting for other tasks.
If you want to make parallel calls you can use bluebird join function
I like the syntax of async functions better than promises, but I use both depending on the situation.
Here is an example of running functions in order before moving to the next function:
async.waterfall([
function(callback1) {
//Do some work, then callback
if (error) {
callback1(errorGoesHere,null);
} else {
callback1(null,successMessageGoesHere);
}
},
function(callback2) {
//Do some work, then callback
if (error) {
callback2(errorGoesHere,null);
} else {
callback2(null,successMessageGoesHere);
}
}
], function (error, success) {
if (error) {
//show an error
}
//all good return the response, etc.
});
If anything in these functions fail, it automatically call the end function to catch the error.
When i am invoking 'userInfo' method using post api,it's always giving a message 'userSchema.save' is not a function.
what am i doing wrong here?
var userModel = mongoose.model('user_details');
module.exports.userInfo = function (req, res) {
var userSchema = new userModel();
new Promise(function (resolve, reject) {
userSchema.emailID= "smid"
userSchema.loginPassword ="smpaswd"
userSchema.contactAddress = [{
addressType: "Communication",
}]
userSchema.favourites = [{
hospitalid: 1234,
}]
resolve();
}).then(function () {
userSchema.save(function (error, data) {
if (error) {
logger.error("Error while inserting record : - " + error)
return res.json({ "Message": error.message.split(":")[2].trim() });
}
else {
return res.json({ "Message": "Data got inserted successfully" });
}
})
}).catch(function (err) {
return res.json({ "Message": err.message });
})
};
I guess the way you are creating your model object is incorrect. Look at this example, In this example we are passing schema definition as "yourSchema" so you may need to pass your schema definition in object creation.
var Tank = mongoose.model('Tank', yourSchema);
var small = new Tank({ size: 'small' });
small.save(function (err) {
if (err) return handleError(err);
// saved!
})
// or
Tank.create({ size: 'small' }, function (err, small) {
if (err) return handleError(err);
// saved!
})
Something like this
//userSchema should exist there
var userModel = mongoose.model('user_details', userSchema);