i am trying to add fileUrl property to the order object inside async function but it won't work
i expect the order object to have a fileUrl property after adding it but it won't work
router.get('/my-orders/:id', isAuth, async (req, res) => {
const id = req.params.id;
try {
const orders = await Order.find({ userId: id });
if (orders.length > 0) {
for (const order of orders) {
const getObjectParams = {
Bucket: bucketName,
Key: order.fileName,
}
const command = new GetObjectCommand(getObjectParams);
const url = await getSignedUrl(s3, command, { expiresIn: 3600 });
// adding fileUrl property to order
order.fileUrl = url;
// it logs only order without fileUrl property
console.log(order);
}
res.send('OK');
}
} catch (error) {
console.error(error);
}
})
In MongoDB, iterating a cursor (which is what Order.find() gives you) will give you MongoDB documents, not plain Javascript objects. If you want plain Javascript objects that you can then manipulate like a plain Javascript object, then use .toObject() on the document.
router.get('/my-orders/:id', isAuth, async (req, res) => {
const id = req.params.id;
try {
const orders = await Order.find({ userId: id });
if (orders.length > 0) {
for (const order of orders) {
const getObjectParams = {
Bucket: bucketName,
Key: order.fileName,
}
const command = new GetObjectCommand(getObjectParams);
const url = await getSignedUrl(s3, command, { expiresIn: 3600 });
// convert from monogdb document to plain Javascript object
const modifiedOrder = order.toObject();
// adding fileUrl property to order
modifiedOrder.fileUrl = url;
console.log(modifiedOrder);
}
res.send('OK');
} else {
res.send('No Orders Found');
}
} catch (error) {
console.error(error);
// always send some response, even for errors
res.sendStatus(500);
}
});
Note, I also cleaned things up so that this request handler is always sending a response, even when no orders are found or when there's an error.
For further discussion of other options, including .lean() and .set(), see this answer.
Related
Like
[
{
"enear": "",
"inten": 1,
"sctor": "Eny",
"topic": "",
"insight": ""
},
{
"enear": "",
"inten": 1,
"sctor": "Eny",
"topic": "",
"insight": ""
}
]
If possible how to write the nodejs code
This is my code
router.post("/post" , async (req,res) => {
const data = new Model(req.map(r => ({
enear: r.body.enear,
inten:r.body.inten,
sctor: r.body.sctor,
topic: r.body.topic,
insight: r.body.insight,
})))
try{
const dataToSave = await data.save()
res.status(200).json(dataToSave)
}catch(error){
res.status(400).json({message:error.message})
}
})
Does map works here?
I have tried using map . Is there any possible way please suggest
You can send an array in the body part and access an array using
req.body and use req.body.map here if it satisifies the condition
Array.isArray(req.body)
router.post("/post" , async (req,res) => {
const { body } = req;
if (Array.isArray(body)) {
const data = new Model(body.map(r => ({
enear: r.body.enear,
inten:r.body.inten,
sctor: r.body.sctor,
topic: r.body.topic,
insight: r.body.insight,
})))
try{
const dataToSave = await data.save()
res.status(200).json(dataToSave)
}catch(error){
res.status(400).json({message:error.message})
}
}
You can specify the array in Body -> Raw (select JSON format):
Then, you should be able to access your data with:
router.post('/post', async (req, res) => {
const { array } = req.body;
try {
const savedData = [];
for (const obj of array) {
const data = await Model.create({
enear: obj.enear,
inten: obj.inten,
sctor: obj.sctor,
topic: obj.topic,
insight: obj.insight,
});
savedData.push(data);
}
res.status(200).json(savedData);
} catch (error) {
res.status(400).json({ message: error.message });
}
});
I am defining the cart variable with await cartsRepo.create({ items: [] });, but I continue to get undefined on cart.
My guess is that the request never resolves, so it never drops into the if conditional, but not sure.
Part of the error was unhandled promise rejection so I threw it all into a try/catch block, but I am still getting undefined on cart.
const express = require("express");
const cartsRepo = require("../repositories/carts");
const router = express.Router();
// Receive a post request to add an item to a cart
router.post("/cart/products", async (req, res) => {
console.log(req.body.productId);
// Figure out the cart!
try {
let cart;
if (!req.session.cartId) {
// // we dont have a cart, we need to create one,
// // and store the cart id on the req.session.cartId property
cart = await cartsRepo.create({ items: [] });
req.session.cartId = cart.id;
} else {
// // We have a cart! Lets get it from the repository
cart = await cartsRepo.getOne(req.session.cartId);
}
const existingItem = cart.items.find(
(item) => item.id === req.body.productId
);
if (existingItem) {
// increment quantity and save cart
existingItem.quantity++;
} else {
// add new product id to items array
cart.items.push({ id: req.body.productId, quantity: 1 });
}
await cartsRepo.update(cart.id, {
items: cart.items,
});
} catch (error) {
console.log(error);
}
res.send("Product added to cart");
});
// Receive a get request to show all items in cart
// Receive a post request to delete an item from a cart
module.exports = router;
The missing piece probably is that I am not using a database but created this repository.js file that where all my data is being stored inside some json files:
const fs = require("fs");
const crypto = require("crypto");
module.exports = class Repository {
constructor(filename) {
if (!filename) {
throw new Error("Creating a repository requires a filename");
}
this.filename = filename;
try {
fs.accessSync(this.filename);
} catch (error) {
fs.writeFileSync(this.filename, "[]");
}
}
async create(attrs) {
attrs.id = this.randomId();
const records = await this.getAll();
records.push(attrs);
await this.writeAll(records);
}
async getAll() {
return JSON.parse(
await fs.promises.readFile(this.filename, {
encoding: "utf8"
})
);
}
async writeAll(records) {
// write the updated 'records' array back to this.filename
await fs.promises.writeFile(
this.filename,
JSON.stringify(records, null, 2)
);
}
randomId() {
return crypto.randomBytes(4).toString("hex");
}
async getOne(id) {
const records = await this.getAll();
return records.find(record => record.id === id);
}
async delete(id) {
const records = await this.getAll();
const filteredRecords = records.filter(record => record.id !== id);
await this.writeAll(filteredRecords);
}
async update(id, attrs) {
const records = await this.getAll();
const record = records.find(record => record.id === id);
if (!record) {
throw new Error(`Record with id ${id} not found`);
}
// record === { email: "test#test.com" }
// attrs === { password: 'mypassword' }
// so attrs is copied over to record object to result in { email: "test#test.com", password: 'mypassword' }
Object.assign(record, attrs);
// take array of records and write it back to JSON file
await this.writeAll(records);
}
async getOneBy(filters) {
const records = await this.getAll();
// iterate through the collection of records - for/of loop because iterating through array
for (let record of records) {
let found = true;
// iterate through all key/value pairs of the filters object - for/in because iterating through object
for (let key in filters) {
// receive every key inside the object and can look at the value inside of object with filters[key]
// it means email or password at filters is the same as email password on record
if (record[key] !== filters[key]) {
// if email and password between filters and record do not match then...
found = false;
}
}
// record was found because filters object key/value pairs and record are same
if (found) {
return record;
}
}
}
};
Just one thing. If you are passing an empty array of items, what is that you are excepting from nothing.
cart = await cartsRepo.create({ items: [] });
And last. What kind of dB you are using?
epascarello mentioned that maybe cartsRepo is not returning what I expect which got me thinking into looking at the repository.js file and sure enough the problem was that I forgot to add a return attrs; to the repository.js file:
async create(attrs) {
attrs.id = this.randomId();
const records = await this.getAll();
records.push(attrs);
await this.writeAll(records);
return attrs;
}
I am making an API that gets a list of image names, then it has to download them one by one from S3 bucket and then send them all as a response.
The issue is that my images are being uploaded but it seems that when I put them in a list as base64 and then try to send the list then the list just comes up empty.
const getImagesById = async (req, res) => {
const { id } = req.params;
const imagesSet = new Map();
try {
const documentFromDB = await document.findOne({ id });
documentFromDB.devices.forEach((device) => {
const images = new Set();
device.images.forEach(item => images.add(downloadFromS3(item)))
imagesSet.set(device.name, JSON.stringify(mapToObj(images))) // tried adding just images also but neither works
});
res.status(200).json(JSON.stringify(mapToObj(imagesSet)));
} catch (e) {
console.log(`An error occurred : ${e.message}`);
res.status(500)
.send(e.message);
}
};
function mapToObj(inputMap) {
let obj = {};
inputMap.forEach(function(value, key){
obj[key] = value
});
return obj;
}
And this is how I get images from S3:
const downloadFromS3 = async (imageName) => {
try {
const image = await S3Utils.downloadFile(BUCKET_NAME, imageName);
if (image.stack) {
return null;
}
const imageBase64 = image.Body.toString('base64');
return imageBase64;
} catch (e) {
console.log(`An error occurred while downloading : ${e.message}`);
throw e;
}
};
This is the response I am getting at the moment:
"{\"{ name: 'Martin'}\":\"{\\\"[object Promise]\\\":{}}\"}"
What I am trying to do is get a lits of device names, map them in a Map as key with value as the base64 list of images and then send it all in a response to the UI to show the images with the names.
What am I doing wrong here?
You just need to add await before call the downloadFromS3 function, consequently changing all the above functions.
const getImagesById = async (req, res) => {
const { id } = req.params;
const imagesSet = new Map();
try {
const documentFromDB = await document.findOne({ id });
await Promise.all(documentFromDB.devices.map(async (device) => {
const images = new Set();
await Promise.all(device.images.map(async item => images.add(await downloadFromS3(item))))
imagesSet.set(device.name, JSON.stringify(mapToObj(images))) // tried adding just images also but neither works
}));
res.status(200).json(JSON.stringify(mapToObj(imagesSet)));
} catch (e) {
console.log(`An error occurred : ${e.message}`);
res.status(500)
.send(e.message);
}
};
function mapToObj(inputMap) {
let obj = {};
inputMap.forEach(function(value, key){
obj[key] = value
});
return obj;
}
basically what I want to achieve is check in a middleware whether an uploaded file has the correct image type (png for example). This is what I have come up with till now:
export const fileCheckMiddleware = (req, res, next) => {
const acceptedImageTypes = ["image/gif", "image/jpeg", "image/png"];
const oldWrite = res.write;
const oldEnd = res.end;
const chunks = [];
res.write = (...restArgs) => {
chunks.push(new Buffer(restArgs[0]));
oldWrite.apply(res, restArgs);
};
res.end = async (...restArgs) => {
if (restArgs[0]) {
chunks.push(new Buffer(restArgs[0]));
}
const body = Buffer.concat(chunks).toString("utf8");
try {
let parsedBody = {};
try {
parsedBody = JSON.parse(body);
} catch (err) {
parsedBody = { data: { unparsedBody: body } };
}
const { variables } = req.body;
console.log("\x1b[1m%s\x1b[0m", "LOG variables", variables.file);
if (variables.file) {
console.log("\x1b[1m%s\x1b[0m", "LOG type", typeof variables.file);
}
} catch (err) {}
oldEnd.apply(res, restArgs);
};
next();
};
The logged type of variables.file is an object. And the result of the console.log is this:
LOG variables Promise {
{ filename: 'trump.jpeg',
mimetype: 'image/jpeg',
encoding: '7bit',
createReadStream: [Function: createReadStream] } }
So how can I access the mimetype here? I tried to map over the keys, variables.file["Promise"],...
Promise is not a key of variables.file, it's the type of variables.file. That means your code starts executing as soon as the HTTP request starts, and the file is received asynchronously, so you have to do something like:
variables.file.then(file => {
// Do whatever you want with the file
next();
});
Or declare the surrounding function as async and do this:
const file = await variables.file;
// Do whatever you want with the file
next();
I make a function checkCompanyPermit with paramater companyIdSource and array allowed.
Example:
companyIdSouce: "req.body.companyId", "req.params.companyId"...
allowed: "user", "admin"...
With parameter companyIdSource as string, I want to convert it to data. It's worked if I use eval(companyIdSource) but it's bad. How can I do another?
I try use Function("return " + companyIdSource)() but it return an error: req is not defined.
const checkCompanyPermit = (companyIdSource, ...allowed) => {
return async (req, res, next) => {
try {
const companyId = eval(companyIdSource) //Bad code, change another code
const company = await Company.findById(companyId)
//... some code
} catch (error) {
next(error)
}
}
}
checkCompanyPermit("req.body.companyId", "manager")
Since you already have access to the req object in your middleware, there is no need to pass the full string representation for req.body.companyId, just the property you need to check will suffice. Use the bracket notation to access the value from req.body object i.e.
const checkCompanyPermit = (companyIdSource, allowed) => {
return async (req, res, next) => {
try {
const companyId = req.body[companyIdSource]
const company = await Company.findById(companyId)
//... some code
} catch (error) {
next(error)
}
}
}
checkCompanyPermit("companyId", "manager")
It's Working For You.
const ObjectId = require('mongodb').ObjectId;
const checkCompanyPermit = (companyIdSource, ...allowed) => {
return async (req, res, next) => {
try {
const companyId = ObjectId('companyIdSource') //Replace here new code
const company = await Company.findById(companyId)
//... some code
} catch (error) {
next(error)
}
}
}
checkCompanyPermit("req.body.companyId", "manager")