In my app I've established an association between the User and Project table. using this code:
User.belongsToMany(Project, {
through: "users_projects"
});
Project.belongsToMany(User, {
through: "users_projects"
});
When I do a simple post request I get the following error:
currentUser.addProject is not a function
app.post("/project", async (req, res, next) => {
try {
const project = await Project.findOrCreate({
where: {
name: req.body.name,
content: req.body.content
}
});
const currentUser = await User.findAll({
where: { id: req.body.userId }
});
console.log(currentUser);
await currentUser.addProject(project[0]);
res.json(project[0]);
} catch (error) {
next(error);
}
});
What could cause this problem?
findAll returns an array, so your code should be
await currentUser[0].addProject(project[0])
However, if you are querying with id, you can use findByPk to get object.
const currentUser = await User.findByPk(req.body.userId);
await currentUser.addProject(project[0])
Related
I have a user schema as follows:
const UserSchema = new mongoose.Schema({
skills: [String]
});
module.exports = mongoose.model("User", UserSchema);
And a Fetch request to delete a skill as follows:
const deleteItem = async (id) => {
try {
await fetch(`http://localhost:5000/api/user/deleteskill`, {
method: "DELETE",
headers: { "Content-Type": "application/JSON", token: accessToken },
body: JSON.stringify({ userid: userid , skill:id}),
})
.then((res) => res.json())
.then((data) => {
console.log("USER SKILLS:", data.userskills);
});
} catch (err) {
console.log(err);
}
};
Server
const deleteSkill = async (req, res) => {
try {
const user = await User.findById(req.body.userid)
//user.skills.pull(req.body.skill);
// removeskill = user.skills.filter(function(item) {
// return item !== req.body.skill
// })
if (user.skills.includes(req.body.skill)) {
res.status(400).json("Item Still Exists");
} else {
res.status(200).json("Item Deleted");
}
} catch (error) {
res.status(500).send({ error: error.message });
}
};
the array is in the following structure
[
'skill1', 'java', 'skill5'
]
I have tried to remove the user skill from the array in several ways but I still get res.status(400).json("Item Still Exists");. What I'm doing wrong?
Use the findOneAndUpdate method to find a document with the user id and update it in one atomic operation:
const deleteSkill = async (req, res) => {
try {
let message = "Item Deleted";
let status = 200;
const user = await User.findOneAndUpdate(
{ _id: req.body.userid },
{ $pull: { skills: req.body.skill } },
{ new: true }
)
if (user && user.skills.includes(req.body.skill)) {
message = "Item Still Exists";
status = 400;
} else if (!user) {
message = "User Not Found";
status = 404;
}
res.status(status).send({ message });
} catch (error) {
res.status(500).send({ error: error.message });
}
};
I believe you want to remove skills from the database then the following function could help you out.
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db("mydb");
var myquery = { userid: userid, skillid: skillid};
dbo.collection("skills").deleteOne(myquery, function(err, obj) {
if (err) throw err;
console.log("1 document deleted");
db.close();
});
});
You have a method of removing elements from arrays, if you want to remove the first one you could use array.shift (more on it here), but if you want to delete it completely from your database you could always, find it and then update it.
User.update({ _id: userid }, { $pull: { "skills": "[skill]" }})
I created an simple CRUD operation in nodejs and mongoose. Updating an user using RESTAPI.
an error message in Insomnia
Error: Server returned nothing (no headers, no data)
URL
http://localhost:1337/api/users/update/63ab9b716065482273e58b75
#PUT METHOD
router.put("/update/:id",updateUser)
const updateUser = async (req,res,next) => {
if (req.params.id === req.user.id) {
try {
const updateuser = await User.findByIdAndUpdate(req.params.id, {
$set:req.body,
})
res.status(200).json(updateuser)
} catch (error) {
next(error)
}
}
}
how to updating with id of user
req.params.id will be of type string, while req.user.id will be probably of type ObjectId.
Can you try this:
if (req.params.id.toString() === req.user.id.toString()) {
As mentioned before req.user.id type is ObjectId. Also you should send an error when ids are not the same.
Example for your code:
const updateUser = async (req, res, next) => {
try {
if (req.params.id !== req.user.id.toString()) {
// Send error in here.
}
const updateuser = await User.findByIdAndUpdate(req.params.id, {
$set: req.body,
});
res.status(200).json(updateuser);
} catch (error) {
next(error);
}
};
updateProfile: async function(req, res) {
try {
const update = req.body;
const id = req.params.id;
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).send('No files were uploaded.');
}
const image = req.files.profileImage;
const cloudFile = await upload(image.tempFilePath);
const profileImage = cloudFile.url
console.log('Loging cloudfile', profileImage)
await User.updateOne(id, { update }, { profileImage }, { new: true },
function(err, doc) {
if (err) {
console.log(err)
}
if (doc) {
return res.status(200).send({ sucess: true, msg: 'Profile updated successful' })
}
});
} catch (error) {
res.status(500).json({ msg: error.message });
}
}
But I'm getting an error of "Callback must be a function, got [object Object]"
I have tried to $set: update and $set: profileImage but still not working.
So the image successful upload into the cloudinary but the update for mongoose is not working.
Upon brief research into the issue, I think you are feeding the arguments in wrong. Objects can be confusing but not to worry.
Your code is:
await User.updateOne(id, { update }, { profileImage }, { new: true }
However, I believe it should be something more like:
await User.updateOne({id: id}, { profileImagine: profileImage, new: true },
The API reference annotates use of the function as:
const filter = { name: 'John Doe' };
const update = { age: 30 };
const oldDocument = await User.updateOne(filter, update);
oldDocument.n; // Number of documents matched
oldDocument.nModified; // Number of documents modified
I'm having an issue with refactoring a function used to create a "post", which then saves it on a "user". It works just fine with the .then() syntax, but I can't seem to figure out how to make this work with async/await.
The post is created, and when I look at the User it is supposed to be saved to, the post id shows up on the User. However, the Post never gets a reference to the User id when created. This is what I have currently.
const create = async (req, res) => {
const userId = req.params.id;
try {
const foundUser = await db.User.findById(userId);
const createdPost = await db.Post.create(req.body);
foundUser.posts.push(createdPost._id);
await foundUser.save((err) => {
if (err) return console.log(err);
});
res.json({ post: createdPost });
} catch (error) {
if (error) console.log(error);
res.json({ Error: "No user found."})
}
}
EDIT: As requested, here is a snippet of my schema for posts.
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const postSchema = new Schema(
{
title: {
type: String,
required: true,
maxlength: 100,
},
description: {
type: String,
maxlength: 300,
},
date: {
type: Date,
default: Date.now(),
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment",
},
],
},
{ timestamps: true }
);
const Post = mongoose.model("Post", postSchema);
module.exports = Post;
The issue is probably here, you're saving the document, but the await here does nothing since you're passing a callback function, so your code does not wait for the response.
await foundUser.save((err) => {
if (err) return console.log(err);
});
There's no need to catch any errors here either since you're in a try catch, so the correct line of code here would be
await foundUser.save()
So, I decided to take a look back at my way of doing this function while using .then(), and I noticed there was a line that I at first thought was unnecessary. I added req.body.user = userId after finding the User. This then gave me the reference to the User on my Post. So, I tried this with my async-await version and it worked! I'm not sure if this is the "right" way to go about this though.
Below I've included the working code:
const create = async (req, res) => {
const userId = req.params.id;
try {
const foundUser = await db.User.findById(userId);
req.body.user = userId;
const createdPost = await db.Post.create(req.body);
foundUser.posts.push(createdPost._id);
await foundUser.save();
res.json({ post: createdPost });
} catch (error) {
if (error) console.log(error);
res.json({ Error: "No user found."})
}
}
I've got a route using Sequelize.js
app.get('/api/users/:username', (req, res) => {
const foundUser = getUserByUsername(req.params.username);
console.log(`foundUser = ${foundUser}`);
return res.send(foundUser);
});
the getUserByUsername function is as follows
const getUserByUsername = username => {
Viewer.findOne({
where: {username}
}).then(response => {
console.log(response.dataValues);//the object with the data I need
return response.dataValues;
});
};
I hoped on getting the object in my const foundUser in my route, but it seems I need to wait until the findOne has been executed, because in my console I can see that the log of foundUser (which is undefined then) is executed before the function getUserByUsername
foundUser = undefined
Executing (default): SELECT `id`, `username`, `instakluiten`, `role`, `createdAt`, `updatedAt` FROM `viewers` AS `viewer` WHERE `viewer`.`username` = 'instak' LIMIT 1;
{ id: 19,
username: 'instak',
instakluiten: 18550,
role: 'moderators',
createdAt: 2016-10-02T16:27:44.000Z,
updatedAt: 2016-10-09T10:17:40.000Z }
How can I make sure that my foundUser will be updated with the data áfter the user has been found?
You have to return the promise that Sequelize creates and then wait for it to resolve. So the getUserByUsername becomes:
const getUserByUsername = username => {
return Viewer.findOne({
where: {username}
}).then(response => {
console.log(response.dataValues);//the object with the data I need
return response.dataValues;
});
};
and in the route:
app.get('/api/users/:username', (req, res) => {
getUserByUsername(req.params.username).then(foundUser => {
res.send(foundUser);
});
});
This is because you need to keep the chain of promises. If you forget to return it, the function returns undefined end even if the promise is finallly resolved, the value it resolves to never gets up back in the chain.
app.get('/api/users/:username', (req, res) => {
getUserByUsername(req.params.username, function(err, result){
const foundUser = result;
console.log(`foundUser = ${foundUser}`);
res.send(foundUser);
});
});
const getUserByUsername = function(username, callback) {
Viewer.findOne({
where: {username}
}).then(response => {
console.log(response.dataValues);//the object with the data I need
return callback(null, response.dataValues);
});
};
You can avoid it with promise or with callback
app.get('/api/users/:username', (req, res) => {
getUserByUsername(req.params.username, function(err, foundUser) {
if (!err) {
console.log(`foundUser = ${foundUser}`);
return res.send(foundUser);
} else {
res.send(err)
}
});
});
const getUserByUsername = (username, callback) => {
Viewer.findOne({
where: {
username
}
}).then(response => {
console.log(response.dataValues); //the object with the data I need
return callback(null, response.dataValues);
});
};