buffer Array to String and then saving in directory - node.js

I am new to React and I am currently facing an issue that I have API written in Express.js in which I am receiving ur fetching whatever it is called an image uploaded from mobile device in a buffer Array and now I have to convert it into string and add extension to it (let say .jpg) and store it into MongoDB Atlas here is my API written in Express ```module.exports.submitFormDataFile = async (req, res) => {
var hkeyArray = [];
const body = req.body;
const collection_name = body.form_collect_name;
const formstructureresult = await FormsStructure.findOne({
collection_name: collection_name
});
formstructureresult.formdata.forEach((eachData) => {
if (eachData.element === 'file') hkeyArray.push(eachData.hkey);
});
// console.log(hkeyArray)
hkeyArray.forEach((element) => {
//In this part I was supposed to convert it in string and save with extension
console.log(req.files[element].data);
});
if (body._id != '' && body._id != null) {
try {
const result = db.collection(
collection_name
);
const results = await result.findOne({
_id: mongoose.Types.ObjectId(body._id)
});
if (!results) {
res.status(200).json({
ERROR: 1,
MESSAGE: 'Invalid Record'
});
} else {
delete body._id;
var newvalues = { $set: body};
const resu = await result.updateOne(results, newvalues);
if (!resu) {
res.status(404).json({
ERROR: '1',
MESSAGE: 'Unable to update'
});
} else {
res.status(200).json({
SUCCESS: '1',
MESSAGE: 'Record Updated Successfully'
});
}
}
} catch (error) {
console.log(error, 'error');
}
}
};
As everything is dynamic so I am fetching hkey which are the name in MongoDB from a collection and fetching other collection based on req.body received and byteArray is also received from req.body and conversion of it into a string I have to update document as shown in the code

Probleum solved! In my case solution was simple I just changed the code accordingly
hkeyArray.forEach((element) => {
//In this part I was supposed to convert it in string and save with extension
var imagedata = req.files[element].data;
let buff = new Buffer.from(imagedata , 'base64');
fs.writeFile(`element+'.jpg'`,buff, function (err) {
if (err) throw err;
console.log('Saved!');
});
body[element] = element+'.jpg'
});

Related

The \"path\" argument must be of type string or an instance of Buffer or URL. Received undefined" error when uploading Multiple file using formidable

I am trying to upload files to aws s3 using formidable . its working fine for single file but when i go with multiple files its showing error The "path" argument must be of type string or an instance of Buffer or URL. Received undefined" in postman
exports.addProduct = asyncHandler(async (req, res) => {
const form = formidable({
multiples: true,
keepExtensions: true,
});
form.parse(req, async function (err, fields, files) {
try {
if (err) {
throw new CustomError(err.message || "Something went wrong", 500);
}
let productId = new Mongoose.Types.ObjectId().toHexString();
// check for fields
if (
!fields.name ||
!fields.price ||
!fields.description ||
!fields.collectionId
) {
throw new CustomError("Please fill all details", 500);
}
// handling images
let imgArrayResp = Promise.all(
Object.keys(files).map(async (filekey, index) => {
const element = files[filekey];
console.log(`line 50 ${element.filepath} `)
console.log(typeof(element))
const data = fs.readFileSync(element.filepath);
console.log("line 62", data);
// console.log(typeof(s3FileUpload))
const upload = await s3FileUpload({
bucketName: config.S3_BUCKET_NAME,
key: `products/${productId}/photo_${index + 1}.png`,
body: data,
contentType: element.mimetype,
});
return {
secure_url: upload.Location,
};
})
);
let imgArray = await imgArrayResp;
const product = await Product.create({
_id: productId,
photos: imgArray,
...fields,
});
if (!product) {
throw new CustomError("Product was not created", 400);
//remove image
}
res.status(200).json({
success: true,
product,
});
} catch (error) {
return res.status(500).json({
success: false,
message: error.message || "Something went wrong",
});
}
});
});
let imgArrayResp = Promise.all(
Object.keys(files).map(async (filekey, index) => {
const element = files[filekey];
console.log(`line 50 ${element.filepath} `)
console.log(typeof(element))
const data = fs.readFileSync(element.filepath);
console.log("line 62", data);
// console.log(typeof(s3FileUpload))
const upload = await s3FileUpload({
bucketName: config.S3_BUCKET_NAME,
key: `products/${productId}/photo_${index + 1}.png`,
body: data,
contentType: element.mimetype,
});
return {
secure_url: upload.Location,
};
})
);
i tried to cosole the element's type its in object . i think element.filepath is not accesable

When using forEach in a Cloud Function, I can't make .sendToDevice() method work

I can send messages to the iOS device using the second function shown below.
I get the document id in the collection name "users" which is at the first level and send the message using the token stored in the tokens subcollection therefore admin.firestore().collection('users').doc(userId).collection('tokens').
I have to change the way the function looks for the user. Rather than relying on the document id of the user, I now need a query in order to find the user. Being a query, unless I'm wrong, I'm forced to use forEach in order to send the message to the user. The function now looks as shown immediately below. In essence, once I know I have the user that needs to receive the message, I'm using the original function format to send the message but the message is never sent. All I see in the logs is Firebase messaging error and I have yet to figure out where the mistake is.
exports.sendMessage = functions.https.onRequest(async (res, response) => {
const body = res.body;
const orderTotal = body.total;
const orderId = String(body.id);
const query = await usersRef.where('token', '==', token).get();
if (query.empty) {
console.log('No matching documents.');
return;
}
query.forEach(doc => {
const tokens = usersRef.doc(doc.id).collection('tokens');
tokens.get()
.then(snapshot => {
const results = [];
snapshot.forEach(doc => {
const fcmToken = doc.data().fcmToken
console.log("fcmToken =>", fcmToken);
results.push(fcmToken);
})
const payload = {
notification: {
title_loc_key: 'notify_title',
subtitle_loc_key: 'notify_subtitle',
body_loc_key: 'notify_body',
badge: '1',
sound: 'cha-ching.caf',
mutable_content: 'true'
},
data: {
'total': orderTotal,
'orderId': orderId
}
}
response.send([results, , payload])
admin.messaging().sendToDevice(results, payload).then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
return { success: true };
}).catch((error) => {
return { error: error.code };
})
})
.catch(err => {
console.log("Error getting documents", err);
});
});
});
This is the original function which I used when using the document id.
exports.sendMessage = functions.https.onRequest(async (res, response) => {
const body = res.body
const orderTotal = body.total
const orderId = String(body.id)
const tokenReference = admin.firestore().collection('users').doc(userId).collection('tokens')
const tokenSnapshots = await tokenReference.get()
const results = []
tokenSnapshots.forEach(tokenSnapshot => {
const fcmToken = tokenSnapshot.data().fcmToken
results.push(fcmToken)
})
const payload = {
notification: {
title_loc_key: 'notify_title',
subtitle_loc_key: 'notify_subtitle',
body_loc_key: 'notify_body',
badge: '1',
sound: 'cha-ching.caf',
mutable_content: 'true'
},
data: {
'total': orderTotal,
'orderId': orderId
}
}
response.send([results, , payload])
admin.messaging().sendToDevice(results, payload).then((response) => {
console.log('Successfully sent message:', response);
return { success: true };
}).catch((error) => {
return { error: error.code };
})
})
Screenshot of the error:
The onRequest() function terminates when you return a response. You are using sendToDevice() after response.send(). Also make sure you are handling all the promises correctly. Try refactoring the using async-await syntax as shown below:
exports.sendMessage = functions.https.onRequest(async (res, response) => {
try {
const body = res.body;
const orderTotal = body.total;
const orderId = String(body.id);
const query = await usersRef.where("token", "==", "TOKEN").get();
if (query.empty) {
console.log("No matching documents.");
return;
}
// Query tokens of all users at once
const tokenSnapshots = await Promise.all(
query.docs.map((user) => usersRef.doc(user.id).collection("tokens").get())
);
// Array of all fcmTokens
const results = tokenSnapshots.reduce((acc, snapshot) => {
acc = [...acc, ...snapshot.docs.map((doc) => doc.data().fcmToken)];
return acc;
}, []);
const payload = { ...FCM_PAYLOAD };
const fcmResponse = await getMessaging().sendToDevice(results, payload);
console.log("Successfully sent message:", fcmResponse);
response.send([results, , payload]);
} catch (error) {
console.log(error);
response.json({ error: "An error occured" });
}
});
Also checkout Terminating HTTP Cloud Functions.
After days of working on this, it turns out there wasn't anything wrong with the function. I don't know how VPN works but the fact that I had it enabled on my iPhone was the reason I wasn't getting the notification.
I paused the VPN and the notification was received.

Use async forEach loop while fetching data from firestore

I have firestore data somewhat like this:
"Support": {
"userid":"abcdxyz",
"message": "hello"
}
I am using nodejs to fetch my data and I also want to show the email address and name of the person who sent this message. So I am using following function:
database.collection("support").get().then(async function (collections) {
var data = [];
console.log("data collected");
collections.forEach(async function (collection) {
var temp = {};
var collectionData = collection.data()
var userInfo = await getUserDetails(collectionData.userId)
temp.name = userInfo.name
temp.supportMessage = collectionData.supportMessage
data.push(temp)
console.log("data pushed")
});
console.log("data posted")
return res.status(200).end(JSON.stringify({ status: 200, message: "Support Message fetched successfully.", data: data }))
}).catch(error => {
return res.status(500).end(JSON.stringify({ status: 500, message: "Error: " + error }))
});
Here the sequence of logs is following: data collected, data posted, data pushed
I want the sequence like this: data collected, data pushed (x times), data posted
Use following code:
database.collection("support").get().then(async function (collections) {
var data = [];
console.log("data collected");
for await(let collection of collections){
var temp = {};
var collectionData = collection.data()
var userInfo = await getUserDetails(collectionData.userId)
temp.name = userInfo.name
temp.supportMessage = collectionData.supportMessage
data.push(temp)
console.log("data pushed")
}
console.log("data posted")
return res.status(200).end(JSON.stringify({ status: 200, message: "Support Message fetched successfully.", data: data }))
}).catch(error => {
return res.status(500).end(JSON.stringify({ status: 500, message: "Error: " + error }))
});
OR
Use can use
var promise = Promise.all(collections.map((collection) =>{
...
return await ... //or a promise
}));
promise.then(() => {
console.log("posted");
return res.status(200).end(...);
})
I solved my answer with the help of #estus comment.
Credit: #estus
var data = [];
var tempCollection = [];
collections.forEach(collection => {
tempCollection.push(collection.data());
});
for (collection of tempCollection) {
var temp = {};
var userInfo = await getUserDetails(collection.userId)
temp.name = userInfo.name
temp.supportMessage = collection.supportMessage
data.push(temp)
}
It solved my problem very easily.
I know this might not the OP's exact use case but if you're interested in compiling the results of a collection query into an array, you can still use the .docs property of a QuerySnapshot to obtain the list of items:
...
const userId = <some-id>;
const usersRef = db.collection(`users`)
const usersSnapshot = await usersRef.where("id", "==", userId).get()
if (usersSnapshot.empty) {
console.log('found no matching user ', userId);
return;
}
console.log(`found ${usersSnapshot.size} user records`);
const userResults = []
// this block here doesn't construct the results array before the return statement
// because .foreach enumerator doesn't await: https://stackoverflow.com/q/37576685/1145905
// usersSnapshot.forEach((doc) => {
// // doc.data() is never undefined for query doc snapshots
// //console.log(doc.id, " => ", doc.data());
// userResults.push[doc.data()];
// });
for (user of usersSnapshot.docs) {
// console.log(user.id, " => ", user.data());
userResults.push(user.data());
}
...
A more detailed example is here

before fetching data in db response is sent by node js

this is my set notification object
var sentNotificationObj = function (notification, eventid, addedorganizerpropic) {
this.notification = notification;
this.eventid = eventid;
this.addedorganizerpropic = addedorganizerpropic;
}
this is my array which is stored notification obect
var notificationSetArray2 = [];
this is my api of getnotification
router.post('/getnotification', function (req, res) {
console.log('in aside');
var id = req.body.userid;
console.log('pos id' + id);
User.findById({ _id: id }, function (err, result) {
if (err) {
console.log('err get notification');
res.statusCode = 500;
res.json({
success: false,
message: "severe error"
});
} else {
this is code fetchin data in data base
for (var i = 0; i < result.notification.length; i++) {
var addedevent = result.notification[i].addedevent;
var notification = result.notification[i].notification;
console.log('added event' + addedevent);
console.log('added noti' + notification);
User.findById({ _id: result.notification[i].addedorganizer }, function (err, addedorganizer) {
if (err) {
console.log('error get added user pofile pic');
} else {
convert image to base64
var base64str = base64_encode(addedorganizer.profileData.profileurl);
console.log(base64str);
console.log(notification);
console.log(addedevent);
var newsentNotificationObj = new sentNotificationObj(notification, addedevent, base64str);
notificationSetArray2.push(newsentNotificationObj);
console.log('succe get added user profile pic');
}
});
}
this is response
res.statusCode = 200;
res.json({
success: true,
notificationArray: notificationSetArray2
})
console.log(notificationSetArray2);
notificationSetArray2.length = 0;
}
});
});
The most simple solution in here to use async library here.
Node runs code in asynchronous way. So it is natural to send response before fetching any data from your database.
By using async you can execute this in a sequence. So it will be solved.
Use async.series method for solve this. For example
async.series(
[
function(callback){
// fetch your data here using mongo with your loop
//
//
callback(); // this will trigger next step (call this after you finished iterating array)
},
function(callback){
// after above code has been executed
// send response here
callback() // call this to proceed
}
],
function(err){
// handle any error in here
}
)
A good example of how to use asyncjs in node

Mongodb not updating the data after put request returns successful

In trying to use the objectid in the mongoose schema as a reference to do a put to update a document in a collection. The console logs its as a success but when I refresh the page or look in the mongo shell nothing changes.
Heres the put in the expressjs router:
router.put('/messageupdate/:empId', function (req, res) {
var values = req.body;
console.log(values);
var empId = req.params.empId;
console.log(empId);
Message.update({empId: empId}, values, function(err, values) {
if (!err) {
res.json("okay");
} else {
res.write("fail");
}
});
})
Heres the service method:
updateServiceWithId(message: Message): Observable<any> {
console.log(message);
const body = JSON.stringify(message);
console.log(body);
const headers = new Headers({'Content-Type': 'application/json'});
return this.http.put('http://localhost:3000/messageupdate/:empId', body, {headers: headers});
}
Heres the client side method that triggers the put:
onUpdateMessage() {
var retVal = confirm("Do you want to continue ?");
if( retVal == true ){
const message = new Message(this.fname,this.lname,this.empId,this.number,this.occu);
console.log(this.fname);console.log(this.lname);
console.log(this.empId);console.log(this.occu);
this.messages.push(message);
this.messageService.updateServiceWithId(message)
.subscribe(
() => console.log('Success!'),
error => console.error(error)
);
}
else{
alert("Edit cancled!");
return false;
}
}

Resources