User Model
const mongoose = require("mongoose");
const validator = require("validator");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const Task = require("./tasks");
const userSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
trim: true
},
age: {
type: Number,
default: 0,
validate(val) {
if (val < 0) throw new Error("age must be a positive number");
}
},
email: {
type: String,
unique: true, //If you use this when you already have data in your db you need to re-populate the db or else it wont work
required: true,
trim: true,
lowercase: true,
validate(val) {
if (!validator.isEmail(val)) throw new Error("Invalid Email");
}
},
password: {
type: String,
minlength: 6,
required: true,
trim: true,
validate(val) {
if (val.includes("password"))
throw new Error("password cant contain password");
}
},
tokens: [
{
token: {
type: String,
required: true
}
}
]
},
{
timestamps: true
}
);
userSchema.virtual("tasks", {
ref: "Task",
localField: "_id",
foreignField: "owner"
});
// Custom function to find user by email and password
// N.B :- we use ".statics for create model functions"
userSchema.statics.findByCredentials = async (email, password) => {
const user = await User.findOne({ email });
if (!user) {
throw new Error("Unable to login");
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
throw new Error("Unable to login");
}
return user;
};
// Hash plain text password before saving
userSchema.pre("save", async function(next) {
const user = this;
if (user.isModified("password")) {
user.password = await bcrypt.hash(user.password, 8);
}
next();
});
//Middleware to delete all user tasks when the user is deleted
userSchema.pre("remove", async function(next) {
const user = this;
await Task.deleteMany({ owner: user._id });
next();
});
//Custom function to create a jwt token for a specific user
// N.B:- we use ".methods" to create instance methods
userSchema.methods.generateAuthToken = async function() {
const user = this;
const token = jwt.sign({ _id: user._id.toString() }, "mysupersecurestring");
user.tokens = user.tokens.concat({ token });
await user.save();
return token;
};
userSchema.methods.toJSON = function() {
const user = this;
const userObject = user.toObject();
delete userObject.password;
delete userObject.tokens;
return userObject;
};
const User = mongoose.model("User", userSchema);
module.exports = User;
Task Model
const mongoose = require("mongoose");
const taskSchema = new mongoose.Schema(
{
description: {
type: String,
required: true,
trim: true
},
completed: {
type: Boolean,
default: false
},
owner: {
type: mongoose.Schema.Types.ObjectId, //use toHexString() to convert to string to avoid errors
required: true,
ref: "User"
}
},
{
timestamps: true //timestamps (plural)
}
);
const Task = mongoose.model("Task", taskSchema);
module.exports = Task;
Task Controller
const express = require("express");
const Task = require("../models/tasks");
const auth = require("../middleware/auth");
const router = new express.Router();
router.post("/tasks", auth, async (req, res) => {
//const task = new Task(req.body);
const task = new Task({
...req.body,
owner: req.user._id
});
try {
await task.save();
return res.status(201).send(task);
} catch (e) {
console.log(e);
// return res.send(e);
}
});
router.get("/tasks", auth, async (req, res) => {
try {
//const allTasks = await Task.find({ owner: req.user._id.toHexString() });
await req.user
.populate({
path: "tasks",
match: {
completed: false
}
})
.execPopulate();
res.send(req.user.tasks);
//res.send(allTasks);
} catch (e) {
res.status(500).send();
}
});
router.get("/tasks/:id", auth, async (req, res) => {
const _id = req.params.id;
try {
const task = await Task.findOne({ _id, owner: req.user._id.toHexString() });
//console.log(_id, req.user._id.toHexString(), task);
if (!task) {
return res.status(404).send();
}
res.send(task);
} catch (e) {
res.status(500).send();
}
});
router.patch("/tasks/:id", auth, async (req, res) => {
const updates = Object.keys(req.body);
const allowedUpdates = ["description", "completed"];
const isValidOperation = updates.every(update =>
allowedUpdates.includes(update)
);
if (!isValidOperation)
return res.status(400).send({ error: "invalid updates!" });
try {
//const task = await Task.findByIdAndUpdate(req.params.id, req.body, {new: true,runValidators: true});
const task = await Task.findOne({
_id: req.params.id,
owner: req.user._id
});
if (!task) return res.status(404).send();
updates.forEach(update => {
task[update] = req.body[update];
});
await task.save();
return res.send(task);
} catch (e) {
return res.status(400).send(e);
}
});
router.delete("/tasks/:id", auth, async (req, res) => {
try {
const task = await Task.findOneAndDelete({
_id: req.params.id,
owner: req.user._id
});
if (!task) return res.status(404).send();
res.send(task);
} catch (e) {
res.status(500).send(e);
}
});
module.exports = router;
In the task controller when I am trying to use the router.get(/tasks) it keeps showing me an error 500(Internal server error). I am trying to populate the virtual properties in the User model which is the tasks. The get task route handler is meant to return all the tasks that specific user created
If you mongoose version is >=6.0
then execPopulate()
is no longer exists.
Reference Removed execPopulate(). Try
await req.user
.populate({
path: "tasks",
match: {
completed: false
}
})
hopefully it will solve your problem.