I couldn't get insert data to firestore database using nodejs - node.js

I tried to insert data as array using node js but then displayed me this error. I added model class .I implemented model class as class components
controller code
const addAnswer = async (req, res, next) => {
const questionName = req.body.questionName;
const answerName = req.body.answerName;
const newDetails = new Details({
//initializing properties
questionName,
answerName
})
newDetails.save().then(() => {
//saving the object to the db
firestore.collection('answersdas').doc().set();
res.status(200).json({ success: true, message: "New answer Added" })//success message
}).catch((error) => {
//error message
res.status(500).json({ success: false, message: "Adding answer failed", error: error.message })
})
}
model
class Answer {
constructor(ans) {
this.ans = ans;
}
module.exports = Answer;

Related

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

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')

Using Mongoose save() inside Formidable's parse() inside NextJS API

Am using formidable package and mongoose in my NextJS app. So I wrote the API call to allow user to upload a photo along with some data. And I process the files using the formidable and it's working fine. But after processing the file, I need to insert some data to my MongoDB through mongoose and then return the API response. If I use await on the save() method of mongoose to save the data, it throws the error saying the parent needs to be async function. But in my case, the parent is form.parse().
Am a bit confused here on how to solve this issue. I think am confused with Promises here.
Here's the stripped down code of my /pages/api/submit.js :
import dbConnect from '../../lib/dbConnect'
import User from '../../models/User'
import formidable from 'formidable'
export default async function handler(req, res) {
await dbConnect()
if (req.method === 'POST') {
const form = new formidable.IncomingForm();
// some config
form.uploadDir = './public/photos/';
form.parse(req, (err, fields, files) => {
//.. some logic
if (err) {
console.log('error parsing the file')
return res.status(400).json( {
error: true,
msg: "Unable to parse the file"
} )
}
// insert some data
var user = new User( { name: 'blah', file_name: 'x', file_size: 'xx' } );
//await user.save();
user.save( err => {
if( err ){
console.log( err )
return false
}
// success
res.status(200).json( {
error: false,
msg: "success"
} ).end()
} )
})
}
}
Just unwrap it from the callback-hell, so you have a nice async/await code
👉Live Demo
const asyncParse = (req) =>
new Promise((resolve, reject) => {
const form = new IncomingForm({ multiples: true });
form.parse(req, (err, fields, files) => {
if (err) return reject(err);
// resolve "returns" the promise so you will have a straighforward logic flow
resolve({ fields, files });
});
});
export default async function handler(req, res) {
console.log("Receiving");
if (req.method === "PUT") {
const result = await asyncParse(req);
// so you can use it here as a normal code flow
res.status(200).json({ result });
}
}
PS. Why necrobumping? Its one of the first Google results, sorry

spread operator does not seem to copy full object

I am trying to implement express error handling middleware. It is working but I don't understand why I have to set error.message equal to the err.message after I copy err to error. Is the spread operator not copying all the attributes from err? When I inspect the err object I don't even see a message or a stack attribute. Also, why is it able to log the error message before the error message is created in the if block.
This is how I am extending the Error
// src/utils/errorResponse.js
class ErrorResponse extends Error {
constructor(message, statusCode) {
super(message)
this.statusCode = statusCode
}
}
module.exports = ErrorResponse
Custom error handler middleware
// src/middleware/error.js
const ErrorResponse = require('../utils/errorResponse')
const errorHandler = (err, req, res, next) => {
let error = { ...err }
console.log({ error.message }) // undefined
error.message = err.message
console.log({ error.message }) // `Resource not found with id of ${err.value}`
// Log to console for dev
// console.log(error.stack)
// Mongoose bad ObjectId
if (err.name === 'CastError') {
const message = `Resource not found with id of ${err.value}`
error = new ErrorResponse(message, 404)
} else {
console.log(error.name)
}
res.status(error.statusCode || 500).json({
success: false,
error: error.message || 'Server Error',
})
}
module.exports = errorHandler
I trigger the error by making a get request with a bad ObjectID
// src/controllers/bootcamp.js
const Bootcamp = require('../models/Bootcamp')
...
// #desc Get single bootcamp
// #route GET /api/v1/bootcamps/:id
// #access Public
exports.getBootcamp = async (req, res, next) => {
try {
const bootcamp = await Bootcamp.findById(req.params.id)
if (!bootcamp) {
return next(err)
}
res.status(200).json({ success: true, data: bootcamp })
} catch (err) {
next(err)
}
}
This is happening because the err parameter you're getting is of Error type object and message key is present in prototype of Error object and spread operator shallow copies keys of object ( excluding prototype keys )
Statement for spread operator from mdn -
The Rest/Spread Properties for ECMAScript proposal (ES2018) added spread properties to object literals. It copies own enumerable properties from a provided object onto a new object.
Shallow-cloning (excluding prototype) or merging of objects is now possible using a shorter syntax than Object.assign().
For reference -
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

How to response data after create data "model.save()" in MongoDB?

I try the response model after create data but it doesn't work. It shows data on "console.log" and it didn't respond when I use "resolve({})".
In the routers.js:
const register = require('./functions/register');
module.exports = router => {
router.get('/', (req, res) => res.end('Welcome to Idol Fan With your Idol !'));
//======REGISTER & LOGIN WITH SOCIAL =====
router.post('/socialuser', (req, res) => {
const social_id = req.body.social_id;
const token = req.body.token;
const name = req.body.name;
const email = req.body.email;
const photoprofile = req.body.photoprofile;
const tokenfirebase = req.body.tokenfirebase;
if (!social_id) {
res.status(400).json({message: 'Invalid Request !'});
} else {
register.registerUser(social_id, name, email, photoprofile, token, tokenfirebase)
.then(result => {
res.status(result.status).json({status: result.status, message: result.message, user: result.user})
})
.catch(err => res.status(err.status).json({message: err.message}));
}
});
}
Function Register.js:
const userfan = require('../models/user');
exports.registerUser = (social_id, name, email, photoprofile, token,
tokenfirebase) =>
new Promise((resolve, reject) => {
const d = new Date();
const timeStamp = d.getTime();
userfan.find({social_id: social_id})
.then(users => {
if (users.length == 0) {
let newUser = new userfan({
social_id: social_id,
name: name,
email: email,
photoprofile: photoprofile,
token: token,
tokenfirebase: tokenfirebase,
created_at: timeStamp
});
newUser.save()
.then(doc => {
console.log("run... " + doc);
resolve({
status: 200,
message: 'User Register Sucessfully !',
user: doc
});
})
.catch(err => {
console.error(err)
if (err.code == 11000) {
reject({status: 409, message: 'User Already Registered !'});
} else {
reject({status: 500, message: 'Internal Server Error !'});
}
});
} else {
return users[0];
}
})
.then(usertemp => resolve({status: 200, message: "Login Successfully !", user: usertemp}))
.catch(err => {
console.log(err.message);
reject({status: 500, message: err.message});
});
});
This is my result after run on server:
As a result and code above. I have a question Why "user: doc" no response?. Thank you so much!
userfan.find.then.then (synchronous since nothing requires waiting) is called before newUser.save.then (asynchronous since under the hood it waits for the DB to answer).
So both resolve are called, but only the first call is considered, and the first one to be called is the one using usertemp. And this one receives undefined as argument, because of the implicit return undefined at the end of userfan.find.then.
Your flow should be:
userfan.find().then(users => {
if (!users.length) {
let newUser = ...
// explicitly return the promise, which will give the created user
return newUser.save().then(doc => {
// format and return the value you want
return {user: doc, message: 'registered'};
});
} else {
// another explicitly returned value, but you already have this
return {user: users[0], message: 'login'};
}
// it's not possible here because we returned before it, but your code reached this point
// and, implicitly, any function ending with no return does:
return undefined;
// this .then receives *either* the promise from newUser.save *or* the object from the else block
}).then(structure => {
structure.status = 200;
return structure; // here structure is {status: 200, message: 'registered'|'login', user: document}
});
Also, note that using the syntax shortcut (without curly braces around the function body) for arrow functions implies the one-line body is returned:
singleArgument => doSomething();
// is actually *strictly* equivalent to
(singleArgument) => { return doSomething(); }
With these ways of writing, it's easy to lose the reflex of writing return when it's needed.

Promise only resolves on the first request

I am developing an API to create a warehouse structure. Because we are using a microservice architecture I need to make a request via rabbitmq to another microservice to generate the address for the new warehouse.
Therefore I use the ampq consume function wrapped in a function which returns a promise. When I hit the endpoint the first time the promise gets resolved and I can continue with my data. But in the second request, the promise will not get resolved.
Maybe it's for an obvious reason but at the moment I don't get it.
So here is my code:
routes.js
router.post('/', (req, res) => {
...
const validate = ajv.compile(warehoseSchema);
const valid = validate(req.body);
if (valid) {
sendToQueue('addressMgmt', req.body.address);
consume()
.then((result) => {
const {
id_address: idAddress,
license_plate: licensePlate,
town,
} = result.body;
createWarehouseHandler(
customernumber, req.body, idAddress, licensePlate, town,
)
.then((insertId) => {
res.json({
id: 'warehouses02',
message: `Warehouse with id ${insertId} successfully created`,
});
})
.catch((err) => {
res.status(err.status).json({
id: err.id,
message: err.message || err.sqlMessage,
});
});
}).catch((err) => {
res.status(err.status).json({
id: err.id,
message: err.message || err.sqlMessage,
});
});
} else {
res.status(417).json({
id: 'warehouses01',
message: `Invalid JSON: ${ajv.errorsText(validate.errors)}`,
});
}
});
const consume = () => new Promise((resolve, reject) => {
const q = 'warehouseMgmt';
amqpCh.consume(q, (msg) => {
const message = JSON.parse(msg.content.toString());
if (Object.keys(message).includes('body')) {
resolve(message);
} else {
const err = new Error();
err.status = 500;
err.id = 'rabbit01';
err.message = 'No message was cosumed';
reject(err);
}
}, { noAck: true });
});
On the first request consume().then() gets called but on the second and following requests, it doesn't.
Thanks for your help

Resources