I am working with my first NodeJS server and I am struggling. Until now I have a GET working perfectly as it is
WORKING
exports.getPosts = (req, res, next) => {
const pageSize = +req.query.pagesize;
const currentPage = req.query.page;
const postMode = req.query.mode;
postQuery = POST.find();
let fetchedposts;
if (pageSize && currentPage) {
postQuery.skip(pageSize * (currentPage - 1))
.limit(pageSize);
}
postQuery.find()
.then(documents => {
fetchedposts = documents;
return post.count();
}).then(count => {
res.status(200).json({
message: 'posts fetched successfully',
posts: fetchedposts,
maxposts: count
});
})
.catch(error => {
res.status(500).json({
message: "Fetching posts failed"
});
});
};
but now I am trying to add a new parameter to the query, mode. What I am trying to achieve is to filter the list by adding extra attributes to the method find(). I have tried to add them like the following code:
NOT WORKING
exports.getposts = (req, res, next) => {
const pageSize = +req.query.pagesize;
const currentPage = req.query.page;
const postMode = req.query.mode;
postQuery = POST.find();
let fetchedposts;
if (pageSize && currentPage) {
postQuery.skip(pageSize * (currentPage - 1))
.limit(pageSize);
}
postQuery.find(**(post) => post.private === true**)
.then(documents => {
fetchedposts = documents;
return post.count();
}).then(count => {
res.status(200).json({
message: 'posts fetched successfully',
posts: fetchedposts,
maxposts: count
});
})
.catch(error => {
res.status(500).json({
message: "Fetching posts failed"
});
});
};
but my server crashed.
ERROR
postQuery.find((post) => post.private === true) TypeError: Cannot read property 'private' of null
How should I do it?
That error means that post is null at some point. You could probably fix it by checking if it is null before checking the private value:
(post) => post && post.private === true
Related
the data is not displayed by REACT and the following error is received: "Objects are not valid as a React child. If you meant to render a collection of children, use an array instead"
The records from MongoDB collection are fetched and gathered in an array of objects. then I use the .map() function to produce the array of elements to be rendered by the Display component. Each
element includes the component which receives two props (firstName and age)
i still do not see where is my mistake...
thanx for help!
SingleRecord.js:
const SingleRecord = (firstName, age) => {
return (
<li className="singe-record">
{firstName} is {age} years old.
</li>
);
}
export default SingleRecord;
Display.js:
function Display() {
const [records, setRecords] = useState();
const dataArray = [];
const fetchRecords = () => {
fetch('http://localhost:3001/users')
.then(async response => {
const isJson = await response.headers.get('content-type')?.includes('application/json');
const data = isJson ? await response.json() : null;
for (const elem of data) {
let elemObj = {
_id: elem._id,
firstName: elem.firstName,
age: elem.age};
dataArray.push(elemObj);
}
setRecords(dataArray);
// check for error response
if (!response.ok) {
// get error message from body or default to response status
const error = (data && data.message) || response.status;
return Promise.reject(error);
}
})
.catch(error => {
console.error('There was an error!', error);
});
}
useEffect(() => {
fetchRecords();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
if (!records) {
return null;
}
const LI = records.map(elem => {
let fn = elem.firstName;
let ageee = elem.age;
return <li><SingleRecord firstName={fn} age={ageee} /></li>
})
return (
<div className="records-display">
<h2>Records:</h2>
<ul className ="records-list">
{records.map(elem => {
let fn = elem.firstName;
let ageee = elem.age;
return <li><SingleRecord firstName={fn} age={ageee} /></li>
})}
</ul>
</div>
);
}
app.js (backend):
const { MongoClient } = require("mongodb");
const uri = "...hidden...";
const client = new MongoClient(uri);
const database = client.db('holdocsDB');
const records = database.collection('records');
app.get('/users', async (req, res) => {
const cursor = await records.find();
const results = await cursor.toArray();
res.send(results);
})
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.json('error');
});
SingleRecord = (firstName, age) should be SingleRecord = ({ firstName, age })
Props aren't passed as individual arguments, they're all in the first argument as an object. Trying to render {firstName} is causing you to try to render the entire props object, and the react error React is telling you that's an issue.
And you aren't using the LI variable. And did you read the error? Get in the habit of always reading errors, don't ignore them.
Error Image
I am trying to create a shopping cart and once I get the data from the client side to the server side after each update, I am getting an internal server error even though everything is working fine and the cart data is being updated in the session.
here is the code from the client side:
const fetchData = async () => {
const res = await axios.get(`http://localhost:3000/cartdata`);
const data = res.data;
console.log(data);
calculateTotals(data);
remove(data);
// postData(data);
}
fetchData();
const postData = async (data) => {
// checkSlice(data);
axios.post('http://localhost:3000/cartdata',{
data: data
}).then((data) => {
console.log('posted', data)
}).catch((err) => {
console.log('error');
});
}
here is the code from the backend:
router.get('/cart', (req, res) => {
let sess = req.session;
let cart = (typeof sess.cart !== 'undefined') ? sess.cart : false;
console.log(cart)
res.render('tarpit/cart', {
pageTitle: 'Cart',
cart: cart,
nonce: Security.md5(req.sessionID + req.headers['user-agent'])
});
});
router.get('/cartdata', (req, res)=>{
let sess = req.session;
let cart = (typeof sess.cart !== 'undefined') ? sess.cart : false;
res.json(cart);
})
router.post('/cartdata',asyncError(async (req, res) =>{
req.session.cart = req.body.data
console.log(req.session.cart);
await req.session.cart.save();
}))
router.post('/cart',asyncError(async(req, res) => {
let qty = parseInt(req.body.qty, 10);
// console.log(qty);
let product = req.body.product_id;
// let format = new Intl.NumberFormat('en-US', {style: 'currency', currency: 'USD'});
if(qty > 0 && Security.isValidNonce(req.body.nonce, req)) {
const mypro = await Products.findOne({_id: product})
let cart = (req.session.cart) ? req.session.cart : null;
const prod = {
id: mypro._id,
title: mypro.title,
price: mypro.price,
qty: qty,
image: mypro.image[0].url,
}
// res.send(prod)
Cart.addToCart(prod, qty, cart);
res.redirect('/cart');
}
else {
res.redirect('/');
}
}));
thanks
Assuming you are using express-session for session please remove await req.session.cart.save(); from your /cardata post method and use following
await req.session.save()
Would like to return an array that has [1year, 1month, etc] and each of those are arrays that contain each document.
Currently, this returns an empty array but when I print the size of the snapshots I get the correct values. Not sure if i'm using push() correctly or if this is an async issue. Thanks.
exports.getStockPrices = functions.https.onRequest((req, res) => {
cors(req, res, () => {
const currentUser = {
token: req.headers.authorization.split('Bearer ')[1]
};
// ! this is a post request
admin
.auth()
.verifyIdToken(currentUser.token)
.then(decodedToken => {
// keep this just in case we want to add anything to do with the user
const user = decodedToken;
// array of collections e.g [1year, 1mo, etc]
const data = [];
// array of documents e.g [18948901, 1984010471, etc]
const documents = [];
db.collection('historical')
.doc(`${req.body.ticker}`)
.listCollections()
.then(collections => {
// each collection is the 1year, 1mo, etc
collections.forEach(collection => {
collection.get().then(querySnapshot => {
console.log('number of documents: ' + querySnapshot.size);
querySnapshot.forEach(doc => {
// doc.data is each piece of stock data
documents.push(doc.data());
});
// each document e.g 1year, 1mo, etc
data.push(documents);
});
});
return data;
})
.then(data => {
return res.json({ data });
})
.catch(err => {
console.log(err);
return res.status(500).send({ error: 'error in getting data' });
});
})
.catch(err => {
console.log(err);
return res.status(500).send({
error: 'error authenticating user, please try logging in again'
});
});
});
});
Due the nature of async calls, your return occurs before your array is being filled.
You can try my example, my firebase function is defined as async this allows me to use await, this statement allows to add a kind of sync for your firestore operations by waiting for the promises.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.eaxmple = functions.https.onRequest(async (req, res) => {
var datax = []
var collections = await db.collection('collection').doc('docid').listCollections()
for (collection in collections) {
content = await collections[collection].get().then(querySnapshot => {
console.log('number of documents: ' + querySnapshot.size);
return querySnapshot.docs.map(doc => doc.data());
});
datax.push(content)
}
return res.json({datax});
});
I wrote this in express JS. the 2 GETs are working but the remaining are not working but I can't see what's wrong with the code. I have a .json file in my directory where I am calling the data from. When I use get id, i get the correct id. When I use POST, it will post only the _id and Date without posting the body of the data.
const studentsArray = readFile();
const studentId = studentsArray.find(student => student._id == req.params.id)
if (studentId) {
res.send(studentId)
} else {
res.status(404).send("student not found")
}
});
router.get("/", (req, res) => {
/* const studentsArray = readFile(filePath); */
res.send(readFile())
});
router.post("/", (req, res) => {
const studentsArray = readFile()
/* const emailCheck = studentsArray.find(student => {
if (students)
}) */
const newStudent = { ...req.body, _id: studentsArray.length + 1, createdOn: new Date() };
studentsArray.push(newStudent)
fs.writeFileSync(filePath, JSON.stringify(studentsArray))
res.status(201).send(`Student ${newStudent._id} was Created Successfully`)
});
router.put("/:id", (req, res) => {
const studentsArray = readFile();
const editedStudent = studentsArray.find(student => student._id == req.params.id)
if (editedStudent)
{
const mergedStudent = Object.assign(editedStudent, req.body)
const position = studentsArray.indexOf(editedStudent)
studentsArray[position] = mergedStudent
fs.writeFileSync(filePath, JSON.stringify(studentsArray))
res.send(mergedStudent)
} else {
res.status(404).send("Student not found")
}
});
router.delete("/:id", (req, res) => {
const studentsArray = readFile();
const studentsRemains = studentsArray.find(student => student._id != req.params.id)
if (studentsRemains.length < studentsArray.length) {
fs.writeFileSync(filePath, JSON.stringify(studentsRemains))
res.status(204).send("Deletion successful")
}
else {
res.status(404).send("Student Not Found")
}
});
Using Express Node.JS along with Mongoose, and I'm trying to add pagination to my get request, however the order in which I'm getting messages is invalid. I get the correct messages with createdAt: -1/createdAt: 'desc', -createdAt, but in reverse order. (Changing to : 1 or 'asc' gives me the oldest messages, and thats not what I need)
const fetchMessages = async (req, res, chatId) => {
try {
const page = req.query.page || 0;
const limit = 25;
const take = req.query.take || limit;
const filter = { chatId: { $eq: chatId } };
let query = await Message.find(filter)
.skip(take * page)
.limit(200)
.sort('-createdAt');
// query = query.sort({ createdAt: 1 });
return res.status(200).json({ data: query });
} catch (e) {
console.log(e);
return res.status(500).json({ message: e });
}
};
Solved it..
const fetchMessages = async (req, res, chatId) => {
try {
// Required pagination param
const page = req.query.page || 0;
// Optional pagination params
const limit = req.query.limit || 25;
const take = req.query.take || limit;
const filter = { chatId: { $eq: chatId } };
let query = await Message.find(filter)
.sort('-createdAt')
.skip(take * page)
.limit(limit);
// Making newest messages come first
query = query.reverse();
return res.status(200).json({ data: query });
} catch (e) {
console.log(e);
return res.status(500).json({ message: e })