ExpressJS res.status(500).json - Cannot read properties of undefined - node.js

I'm trying to setup a MeiliSearch index to be populated when my backend server (NodeJS/ExpressJS) starts. Below is my code:
const withDB = async (operations, res) => {
try {
const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true });
const db = client.db('database-name');
await operations(db);
client.close();
} catch (error) {
res.status(500).json({ message: 'Error connecting to db', error });
}
}
app.listen(8000, async(res) => {
withDB(async (db) => {
const searchReports = await db.collection('reports').find().limit(500).toArray()
res.status(200).json(searchReports);
const searchIndex = new MeiliSearch({ host: 'http://127.0.0.1:7700' })
searchIndex.index('Reports').addDocuments(searchReports)
.then((res) => console.log(res));
}, res)
});
Everything works fine apart from when I add either of the line referencing 'res'. At that point I get the error:
res.status(500).json({
^
TypeError: Cannot read properties of undefined (reading 'status')

Related

Cannot conect to redis in Node

I'm trying to create a basic caching app just to test redis. Im using Redis Version: 4.0.6.
First I was getting error clientclosederror: the client is closed.
Then, after reading the docs, I added
let client;
(async ()=> {
client = redis.createClient()
await client.connect()
})();
But now, when trying on Postman, it just hangs, no response is returned
Full Code:
const express = require("express");
const redis = require("redis");
const axios = require('axios')
const app = express();
let client;
(async ()=> {
client = redis.createClient()
await client.connect()
})();
app.get('/result', async (req, res) => {
const searchTerm = req.query.name;
try {
await client.get(searchTerm, async (err, result) => {
console.log('cached called')
if (err) throw err;
if (result) {
res.status(200).send({
result: JSON.parse(result),
message: "data retrieved from the cache"
});
}
else {
const result = await axios.get(`https://api.agify.io/?name=${searchTerm}`);
await client.set(searchTerm, JSON.stringify(result.data));
return res.status(200).send({
result: result.data,
message: "cache miss"
});
}
})
} catch (error) {
console.log('get error', error)
return res.status(500).send({ message: error.message })
}
})
app.listen(process.env.PORT || 3000, () => {
console.log("Node server started");
});
client.get doesn't need a callback function. It's async. My guess is that it's never getting called and thus Express is not returning anything.
Try this instead:
const result = await client.get('foo')
if (result !== null) {
// it's a hit
} else {
// it's a miss
}

Writing Mocha Chai Test cases for NodeJs Controllers

I am new to unit testing. I am trying to write test cases for controller.js files for nodejs microservices files. I am unable to understand where I am going wrong. Always throws an error "TypeError: Cannot read property 'empId' of undefined" for 2 of these properties.
This is the controller code:
const crmgDetails = db.crmgResource_details;
const employeeProposal = db.employee_Proposal;
const Op = db.Sequelize.Op;
const raDetails = db.crmgRaSheet_entity;
let results = [];
Sequelize = require('sequelize')
exports.findOne = (req, res) => {
console.log(req.body.empId);
crmgDetails.findAll({where: {
resEmployeeNumber: req.body.empId
}
})
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Some error occurred while retrieving tutorials."
});
});
};
exports.findMatchingDemandsForRmg = (req,res) => {
let proposedDemands = [];
employeeProposal.findAll({
where: {
emp_id: req.body.empId,
demandSbu : req.body.sbu
}
}).then(proposedEmployee => {
console.log('proposedEmployee',proposedEmployee);
if(proposedEmployee.length === 0){
crmgDetails.findAll({
where: {
resEmployeeNumber: req.body.empId,
demandSbu: req.body.sbu
}
}).then(matchingDemands => {
console.log('matchingDemands ',matchingDemands)
proposedDemands = matchingDemands;
})
}
else{
console.log("crmg Employee")
console.log(proposedEmployee)
for(let employee of proposedEmployee){
crmgDetails.findOne({
where: {
demandUid: employee.demandUid,
resEmployeeNumber: req.body.empId,
demandSbu: req.body.sbu
}
}).then( crmgProposed=> {
proposedDemands.push(crmgProposed);
})
}
}
setTimeout(() => {
console.log(proposedDemands)
res.send(proposedDemands);
}, 3000);
}).catch((err)=>{
res.status(500).send({
message:
err.message || "Some error occurred while retrieving tutorials."
});
})
}
exports.getResourceAllocationDetails = (req,res) => {
employeeProposal.findAll({
include: {
model: raDetails
},
where: Sequelize.and(
{activeFlag : true},
Sequelize.or({status:"Accepted By RMG"},
{status:"Rejected"}
))
}).then(employees => {
res.send(employees)
})
}
This is the test file I tried to write without my head:
const CrmgRaSheetModel = require('../controllers/crmgResource_Details.controller')
describe('Check for succcessful fetech API call', () => {
it('property getResourceAllocationDetails should be called', async () => {
CrmgRaSheetModel.getResourceAllocationDetails((res) => {
expect(res).to.be.an('object')
return res.json()
})
});
it('property findMatchingDemandsForRmg should be called', async () => {
CrmgRaSheetModel.findMatchingDemandsForRmg((res) => {
expect(res).to.be.an('object')
return res.json()
})
});
it('property findOne should be called', async () => {
CrmgRaSheetModel.findOne((res) => {
expect(res).to.be.an('object')
return res.json()
})
})
})
from test file you are calling controller method with only res, so no chance to send your input as your body.
So pass req,res both and pass your input value in req

UnhandledPromiseRejectionWarning when adding a new record to DB

I am trying to add new records to my MongoDB database. The records come in the form of an array, and then, for each record, I add it as a new item to MongoDB.
The problem is that every time I try to add some records (30-50 records) I get this message:
UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch()
followed by this one:
UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
This is the snippet I use for adding records:
// update the blacklist with a new entry
router.post("/updateBlacklist", async (req, res) => {
req.body.product_id.forEach(async element => {
const blacklistItem = new Blacklist({ product_id: element });
try {
const savedItem = await blacklistItem.save();
res.json(savedItem);
} catch (err) {
console.log(err);
res.json({ message: err });
}
});
});
The same warning appears also when I try to download some photos using this function:
router.post("/product_ids", async (req, res) => {
await downloadPhotos(req.body.items_id);
});
the function I call inside this route:
const axios = require("axios");
const download = require("./utils/download");
const downloadPhotos = async itemsIDs => {
try {
console.log(itemsIDs.length);
await itemsIDs.forEach(ID => {
axios
.get(
`https://${process.env.SHOPIFY_API_KEY}:${
process.env.SHOPIFY_PASSWORD
}#blablabla.myshopify.com/admin/products/${ID}/images.json?fields=id, src`
)
.then((req, res) => {
console.log(req.data.images[0].src);
download(req.data.images[0].src, req.data.images[0].id, 3000);
});
});
} catch (err) {
console.log(err);
}
};
and the download function:
const Fs = require("fs");
const Path = require("path");
const Axios = require("axios");
async function downloadImage(url, filename, timeout) {
const appDir = Path.dirname(require.main.filename);
const path = Path.resolve(appDir, "images", `${filename}.jpg`);
const writer = Fs.createWriteStream(path);
const response = await Axios({
url,
method: "GET",
responseType: "stream",
timeout: timeout
});
response.data.pipe(writer);
return new Promise((resolve, reject) => {
writer.on("finish", resolve);
writer.on("error", reject);
});
}
module.exports = downloadImage;
What am I doing wrong in this approach?
This error:
UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
It's because of these lines:
res.json(savedItem);
res.json({ message: err });
You're running these lines several times, because they are inside the loop, you can't respond a request more than once because the connection it's closed after the first call.
Try with this:
router.post("/updateBlacklist", async (req, res) => {
const savedList = [];
req.body.product_id.forEach(async element => {
const blacklistItem = new Blacklist({ product_id: element });
try {
const savedItem = await blacklistItem.save();
savedList.push(savedItem)
} catch (err) {
console.log(err);
savedList.push({ message: err });
}
});
res.json(savedItem);
});
UPDATE (suggestion):
router.post("/updateBlacklist", async (req, res) => {
const items = req.body.product_id.map(element =>
new Blacklist({ product_id: element })
});
const result = await Blacklist.insertMany(items); // not sure about the syntax
res.json(result);
});

how to troubleshhot slow queries using mongoose

I have set up a node/mongoose API project for the first time. I am having trouble trying to figure out why some of the queries are taking so long. I am trying to use, explain method but I cannot figure out where to put it.
mongoose.connect(mongo.uri, {useNewUrlParser: true})
.then(() => console.log('Connected'))
.catch(error => console.log('Error' + error))
mongoose.Promise = Promise
Object.keys(mongo.options).forEach((key) => {
mongoose.set(key, mongo.options[key])
})
mongoose.Promise = Promise
/* istanbul ignore next */
mongoose.Types.ObjectId.prototype.view = function () {
return { id: this.toString() }
}
/* istanbul ignore next */
mongoose.connection.on('error', (err) => {
console.error('MongoDB connection error: ' + err)
process.exit(-1)
})
export default mongoose
export const create = ({ body }, res) => {
const action = (error, collection) => {
if (error) failure(res.status(500).json({ status: 'error', error: error }))
else {
collection.find({'Series.ExcludeFromAudit': false}).toArray((error, data) => {
error && failure(res.status(500).json({ status: 'error', error: error }))
!error && success(res.status(200).json({ data }))
})
}
}
mongoose.connection.db.collection('MetrostudyProjects', action)
}

Sample code to query MongoDB in node.js (lambda) code

I'm new to node.js and trying to create a lambda function that queries a collection from MongoDB.
Here is a code I found as a starting point:
'use strict';
const MongoClient = require('mongodb').MongoClient;
const ATLAS_URI = "mongodb://lambdaUser:PASSWORD#cluster0-shard-00-00-ddlwo.mongodb.net:27017,cluster0-shard-00-01-ddlwo.mongodb.net:27017,cluster0-shard-00-02-ddlwo.mongodb.net:27017/mydb?ssl=true&replicaSet=Cluster0-shard-0&authSource=admin";
let cachedDb = null;
function connectToDatabase(uri) {
console.log('=> connect to database');
if (cachedDb) {
console.log('=> using cached database instance');
return Promise.resolve(cachedDb);
}
return MongoClient.connect(uri)
.then(db => { cachedDb = db; return cachedDb; });
}
function queryDatabase(db) {
console.log('=> query database');
return db.collection('sensordata').find({}).toArray()
.then(() => { return { statusCode: 200, body: 'success' }; })
.catch(err => { return { statusCode: 500, body: 'error' }; });
}
exports.handler = (event, context, callback) => {
connectToDatabase(ATLAS_URI)
.then(db => queryDatabase(db))
.then(result => {
console.log('=> returning result: ', result);
context.succeed(result);
})
.catch(err => {
console.log('=> an error occurred: ', err);
context.failed(err);
});
};
This code works fine, but I don't know how to recover the data from the query...
Looking other code I see there is a function(err,data) inside the find(), but in this case I don't know how to insert that or modify the code to return the data instead of the {statuscode: 200, body: 'success'} json object.
I would appreciate any help.
Thanks
Gus

Resources