I have 2 tables: user and material which have a m:m relationship. The intersection entity is journalMaterials. I am trying to send a POST request to insert into journalMaterials. Also, this table has 2 attributes: recycledQuantity and recycleDate. I tried something, but if i insert with a materialId which doesn't exist it doesn't give me "not found".
app.post('/users/:uid/materials/:mid', (req, res, next) => {
User.findById(req.params.uid)
.then((user) => {
if (user){
let journalMaterial = req.body
journalMaterial.userId = user.id
Material.findById(req.params.mid)
.then((material) => {
if (material){
journalMaterial.materialId = material.id
return JournalMaterial.create(journalMaterial)
}
else{
res.status(404).send('not found')
}
})}
else{
res.status(404).send('not found')
}
})
.then(() => {
if (!res.headers){
res.status(201).json('created')
}
})
.catch((err) => next(err))
})
I've solved it. Here is the correct code.
app.post('/users/:uid/materials/:mid', (req, res, next) => {
const { uid, mid } = req.params;
Promise.all([
User.findById(uid),
Material.findById(mid)
])
.then(([user, material]) => {
if (user && material) {
let journalMaterial = req.body
journalMaterial.userId = user.id
journalMaterial.materialId = material.id
res.status(201).json('created')
return JournalMaterial.create(journalMaterial)
}
res.status(404).send('not found')
})
.catch(err => next(err));
})
Slightly re-wrote this to make it a bit more readable. Removed your nested promise calls... (let's not dive into promise hell when they try to get rid of callback hell..)
app.post('/users/:uid/materials/:mid', (req, res, next) => {
const { journalMaterial } = req.body;
const { uid, mid } = req.params;
Promise.all([
User.findById(uid),
Material.findById(mid)
])
.then(([user, material]) => {
if (user && material) {
journalMaterial.userId = user.id;
journalMaterial.materialId = material.id;
return JournalMaterial.create(journalMaterial);
}
res.status(404).send('not found');
})
.then(() => {
if (!res.headers) {
res.status(201).json('created');
}
})
.catch(err => next(err));
});
Your check against if(user) currently passes. It seems that if that's what is happening, you're always getting an object back. Lots of databases generally don't simply return a null or false value, but rather an object with a bunch of meta data. In that object is generally the data you requested (ie, user.data.id, but it may be that user.data is NULL). Can you verify what the exact contents of Users is? It's evaluating to truthy, thus it must have something in it.
Related
I am trying to make a db call insides a loop and want to add that data into one object and then send this object to user, but I am getting only a empty object at the user end.
I already checked this one asynchronous response into a loop in javascript NodeJS
router.get('/collection', (req, res) => {
const Data = {}
Section.find({})
.then(sections => {
sections.map(section => {
let id = section._id;
Product.find({section: id})
.then(products => {
// console.log(products)
Data[section.title] = {
title: section.title,
routeName: section.title,
id,
items: products
}
console.log(Data)
})
.catch(err => {
return res.status(500).json(err)
})
})
return res.json(data)
})
.catch(err => {
return res.status(500).json(err)
})
})
I want the output to be like :-
{
food : {
items: [...]
},
vegetable: {
items: [...]
}
}
food and vegetable are keys which will be obtained from a Database Call and items in each keys are returned from a seperate call to database.
return res.json(data) is executed before any of the mapped Product-promises are resolved (also there's a typo since you're returning data instead of Data). One way to do this is to map the find-promises and to use Promise.all on the mapped array. Something like:
router.get('/collection', (req, res) => {
const Data = {}
Section.find({})
.then(sections => {
const sectionProductPromises = sections.map(section => {
let id = section._id;
return Product.find({
section: id
})
.then(products => {
Data[section.title] = {
title: section.title,
routeName: section.title,
id,
items: products
}
});
});
return Promise.all(sectionProductPromises);
})
.then(() => {
res.json(Data)
})
.catch(err => {
res.status(500).json(err)
});
});
I am attempting to check if a user owns a document before updating it or deleting it, and would like to keep this as DRY as possible. Ideally, I would not have to make two calls to the database where I would first findById().then(doc => {check if user owns document and then -> doc.findByIdAndUpdate() }) but rather keep this as one call to the DB.
I am constantly having to execute this check on express routes and have thought about implementing this layer of logic on the mongoose .pre('update') middleware. but am unaware how to pass the incoming userid from the req object to my middleware validation function?
Are there any better layers to implement this checking functionality? or am I going to have to make the two requests to the database every time I want to check if a user owns a document and write this out in every express route?
My current implementation is:
const addDocToDoc = (req, res, next) => {
let doc1id = req.params.id;
let doc2id = req.params.doc2id;
Doc1.findById(doc1id)
.then(doc1 => {
if(userCanAlter(doc1, req.user, res)) {
doc1.doc2s.push(doc2id)
return doc1.save().then(updatedDoc1 => res.send(updatedDoc1))
}
}).catch(next)
}
Where userCanAlter() looks like this:
function userCanAlter(instance, user, res) {
if (!instance) { res.status(404).send("Document does not exist."); return false}
if (instance.user != user) { res.status(401).send("User unauthorized"); return false}
else return true;
}
Obviously, this is a very simple update but the more complex updates would require more configuration before saving.
Current implementation in question found to be the best & DRY’est implementation.
You can simply wrap your user in find query and use findOne(), Something like:
const addDocToDoc = (req, res, next) => {
const {
user = ''
} = req;
const {
id = '', doc2id = ''
} = req.params;
Doc1.findOne({
_id: id,
user
})
.then(doc => {
if (!doc) {
return res.status(400).json({
message: 'User Not Found!!'
});
}
doc.doc2s.push(doc2id);
doc.save()
.then(updatedDoc1 => res.status(200).json(updatedDoc1))
.catch(err => res.status(500).json({
message: 'Error While Updating!!',
error: err
}));
})
.catch(err => res.status(500).json({
message: 'Error While Fetching!!',
error: err
}));
}
Also I'd suggest if you work a bit on naming things, as this may mess up things a few times.
In case if you wanna throw specific error for unauthorized user, you can stick to your way of implementation, just don't need a separate method to check ownership. I've simplified it with async/await and the code is:
const addDocToDoc = async (req, res, next) => {
try {
const {
user = ''
} = req;
const {
id = '', doc2id = ''
} = req.params;
const doc = await Doc1.findById(id);
if (!doc || !doc.user || doc.user !== user) {
return res.status(401).json({
message: 'Unauthorized User!!'
});
}
doc.doc2s.push(doc2id);
const updatedDoc1 = await doc.save();
return res.status(200).json(updatedDoc1);
} catch (err) {
res.status(500).json({
message: 'Error While Updating Record!!',
error: err
});
}
}
Ps: You may need some modification as i couldn't get a chance to run it.
Hope this helps :)
In the below code, when I remove the .where() from my query the query works and I get my comments returned. However, when I use the where query to try and find a comment bound to a post (scream) id, i get a blank array. Am I using .where() incorrectly? Any help would be appreciated.
exports.getScream = (req, res) => {
let screamData = {};
db.doc(`/screams/${req.params.screamId}`)
.get()
.then((doc) => {
screamData = doc.data();
screamData.screamId = doc.id;
return db
.collection('comments')
.where('screamId', '==', screamData.screamId) //query that doesnt seem to be working
.orderBy('createdAt', 'desc')
.get();
})
.then((data) => {
screamData.comments = [];
data.forEach((doc) => {
screamData.comments.push(doc.data());
});
return res.json(screamData);
})
.catch((err) => {
console.error(err);
res.status(500).json({ error: err.code });
});
}
Firestore document model
{
screamId: “id of post commenting on”,
body: “content of comment”,
userHandle: “username of comment”
}
I am getting an error that seems to suggest I'm not returning some of my statements, but I think I'm doing everything correctly. Here's the warning:
Warning: a promise was created in a handler at /src/api/podcasts.js:51:18 but was not returned from it
This is the code of the function in question:
'findPodcastById': (db, podcastId, callback) => {
var queryString = "SELECT * FROM podcasts WHERE id=$1;";
db.one(queryString, [podcastId])
.then((result) => {
return callback(null, result);
})
.catch((err) => {
return callback(err, null);
});
},
And the parent function that it's called from:
app.post('/getepisodes', (req, res, next) => {
var podcastId = req.body.podcastId;
var userId = req.body.userId;
var podcast;
podcasts.findPodcastByIdAsync(db, podcastId)
.then((result) => {
podcast = result;
return request(podcast.rss);
})
.then((result) => {
return podcastParser.parseAsync(result, {})
})
.then((result) => {
return Promise.resolve(result.channel.items);
})
.map((item) => {
var date = new Date(item.pubDate).toLocaleString();
return podcasts.addEpisodeAsync(db, podcast.id, item.title, item.enclosure.url.split('?')[0], striptags(item.description), date, item.duration);
})
.map((episode) => {
return posts.addPostAsync(db, 'podcast', episode.id, episode.title, episode.description);
})
.then(() => {
return podcasts.findEpisodesByPodcastIdAsync(db, podcastId, userId);
})
.then((result) => {
return res.json(result);
})
.catch((err) => {
next(err);
});
});
I have a return statement in each promise block, so I'm not sure what I'm doing wrong, I would really appreciate some help!
findPostCastBy id is not returning the promise, try this
'findPodcastById': (db, podcastId) => {
return db.one("SELECT * FROM podcasts WHERE id=$1;", [podcastId])
}
I have tried everything and can't figure out what i am doing wrong. I have no problem posting data from the client to the server but the other way around i can't get it to work.
The only response i get in my client is ReadableByteStream {}.
This is my code on the client:
export function getAllQuestionnairesAction(){
return (dispatch, getState) => {
dispatch(getAllQuestionnairesRequest());
return fetch(API_ENDPOINT_QUESTIONNAIRE)
.then(res => {
if (res.ok) {
console.log(res.body)
return dispatch(getAllQuestionnairesSuccess(res.body));
} else {
throw new Error("Oops! Something went wrong");
}
})
.catch(ex => {
return dispatch(getAllQuestionnairesFailure());
});
};
}
This is my code on the server:
exports.all = function(req, res) {
var allQuestionnaires = [];
Questionnaire.find({}).exec(function(err, questionnaires) {
if(!err) {
console.log(questionnaires)
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ a: 1 }));
//res.json(questionnaires)
}else {
console.log('Error in first query');
res.status(400).send(err);
}
});
}
I'm doing some guesswork here, since I'm not sure what flavor of fetch you are currently using, but I'll take a stab at it based on the standard implementation of fetch.
The response inside the resolution of fetch typically does not have a directly readable .body. See here for some straight forward examples.
Try this:
export function getAllQuestionnairesAction(){
return (dispatch, getState) => {
dispatch(getAllQuestionnairesRequest());
return fetch(API_ENDPOINT_QUESTIONNAIRE)
.then(res => {
if (res.ok) {
return res.json();
} else {
throw new Error("Oops! Something went wrong");
}
})
.then(json => {
console.log(json); // response body here
return dispatch(getAllQuestionnairesSuccess(json));
})
.catch(ex => {
return dispatch(getAllQuestionnairesFailure());
});
};
}