Mongoose - pushing refs - cannot read property "push" of undefined - mongodb

I would like to add a category and then if successed, push it's ref to user' collection. That's how I'm doing this:
That's mine "dashboard.js" file which contains categories schema.
var users = require('./users');
var category = mongoose.model('categories', new mongoose.Schema({
_id: String,
name: String,
ownerId: { type: String, ref: 'users' }
}));
router.post('/settings/addCategory', function(req, res, next) {
console.log(req.body);
var category_toAdd = new category();
category_toAdd._id = mongoose.Types.ObjectId();
category_toAdd.name = req.body.categoryName;
category_toAdd.ownerId = req.body.ownerId;
category.findOne({
name: req.body.categoryName,
ownerId: req.body.ownerId
}, function(error, result) {
if(error) console.log(error);
else {
if(result === null) {
category_toAdd.save(function(error) {
if(error) console.log(error);
else {
console.log("Added category: " + category_toAdd);
<<<<<<<<<<<<<<<<<<<THE CONSOLE LOG WORKS GOOD
users.categories.push(category_toAdd);
}
});
}
}
});
Here is my "users.js" file which contains "users" schema.
var categories = require('./dashboard');
var user = mongoose.model('users', new mongoose.Schema({
_id: String,
login: String,
password: String,
email: String,
categories: [{ type: String, ref: 'categories' }]
}));
So, the category add proccess works well and I can find the category in database. The problem is when I'm trying to push the category to user.
This line:
users.categories.push(category_toAdd);
I get this error:
Cannot read property "push" of undefined.
I need to admit once more that before that pushing there is console.log where the category is printed properly.
Thanks for your time.

The users object is a Mongoose model and not an instance of it. You need the correct instance of the users model to add the category to.
dashboard.js
...
category_toAdd = {
_id: mongoose.Types.ObjectId(),
name: req.body.categoryName,
ownerId: req.body.ownerId
};
// Create the category here. `category` is the saved category.
category.create(category_toAdd, function (err, category) {
if (err) console.log(err);
// Find the `user` that owns the category.
users.findOne(category.ownerId, function (err, user) {
if (err) console.log(err);
// Add the category to the user's `categories` array.
user.categories.push(category);
});
});

Related

How do I add a subdocument's data to a parent document (using mongoose)?

I am creating a MERN app and have a series of mongoose schema that are connected.
The hierarchy goes: Program -> Workout -> Exercise -> Set
Here is the model code for each Schema:
Program Schema
const programSchema = mongoose.Schema({
program_name:{
type: String,
},
workouts:[{
type: mongoose.Types.ObjectId,
ref: 'Workout'
}]
Workout Schema
const workoutSchema = mongoose.Schema({
workout_name:{
type:String
},
exercises: [{
type: mongoose.Types.ObjectId,
ref: 'Exercise'
}]
Exercise Schema
const exerciseSchema = mongoose.Schema({
exercise_name:{
type:String
},
notes:{
type:String
},
sets:[{
type: mongoose.Types.ObjectId,
ref: 'Set'
}]
Set Schema
const setSchema = mongoose.Schema({
weight:{
type: String
},
repetitions:{
type: String
},
rpe:{
type: String
}
My question is, now that they are all separate. How do I link a specific Set to a Exercise? or a specific Exercise to a Workout? etc. How do I reference them to each other so that I can create a whole program with various workouts, and each workout having various exercises, etc.
I would appreciate any wisdom. Thank you
For more info, here are the controllers.
Program Controller (CREATE NEW PROGRAM)
const createProgram = async (req, res) => {
//const {program_name, workouts} = req.body
try {
const program = new Program(req.body) // create a new program with the information requested
await program.save() // save it to database
res.status(201).send(program) // send it back to user
} catch (e) {
res.status(500).send(e)
}
WORKOUT CONTROLLER (CREATE NEW WORKOUT)
const createWorkout = async (req, res) => {
const {workout_name} = req.body
try {
const workout = await new Workout({
workout_name
})
await workout.save()
res.status(201).send(workout)
} catch(e) {
}
EXERCISE CONTROLLER (CREATE NEW EXERCISE)
const createExercise = async (req, res) => {
const { exercise_name='', notes='', sets } = req.body
try {
const exercise = await new Exercise({
exercise_name,
notes,
sets
})
await exercise.save()
res.status(201).send(exercise)
} catch (e) {
console.log(e)
}
SET CONTROLLER (CREATE NEW SET)
const createSet = async (req, res) => {
const {repetitions='', weight='', rpe=''} = req.body
try {
const set = await new Set({
weight,
repetitions,
rpe
})
await set.save()
res.status(201).send(set)
} catch (e) {
res.status(500).send(e)
}
The way I do it is on save I add the id to the attributed array. So i'll give you an example for one of your Routers then hopefully you can understand enough to do the rest.
For workouts you want to add it to a program when it's created. so when you create it, just add the id to the program you want to add it to.
Like so:
const {workout_name} = req.body
try {
const newWorkout = await Workout.create({
workout_name
})
Program.updateOne(
{ _id: req.params.ProgramId },
{ $addToSet: { workouts: newWorkout._id }},
)
res.status(201).send(workout)
} catch(e) {
}
So basically after creating your workout, you add that workout ID to the workouts array of the parent object. You would do the same for the rest of your Routers.

why does this populate give me a not found function error?

How can I execute this populate so that I can get the username of the person that does the tweet? I've tried with the function getusername() but it is not working as it gives me a tweetsSchema.findOne is not a function error.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var tweetsSchema = new Schema(
{
tweets: { type: String, required: true }, //reference to the associated book
replies: { type: String, required: false },
username: { type: Schema.Types.ObjectId, ref: 'users' }
}
);
// Virtual for bookinstance's URL
function getUsername(tweets){
return tweetsSchema.findOne({ tweets: tweets })
.populate('username').exec((err, posts) => {
console.log("Populated User " + username);
})
}
getUsername()
//Export model
module.exports = mongoose.model('tweets', tweetsSchema);
currently the function you have defined is just a function and haven't defined on the Schema of yours and not exported.
you might want to use static in mongoose
tweetsSchema.static('getUsername', async function(tweets){
return await tweetsSchema.findOne({ tweets: tweets })
.populate('username').exec((err, posts) => {
console.log("Populated User " + username);
})
})

How can I make a todo or more get saved in an array property of the User that created them, in MongoDB?

I want to make all the newly created todos get saved an be associated with the signed in user in the MongoDB. What I have sa far is this:
User.js
const UserSchema = new mongoose.Schema({
...
todos: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Todo' }]
});
Todo.js
const TodoSchema = new mongoose.Schema({
...
creator: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
});
And when I create the task I have no idea how am I supposed to make that relationship between the User and the todos:
todoController.js
exports.createTodo = function (req, res) {
const { text, creator } = req.body;
const newTodo = new Todo({ text, creator });
newTodo.save((err) => {
if (err) {
return res.status(400).json({
message: `Todo wasn't saved beacause: ${err}`
});
}
res.json({
message: `Todo created successfuly`,
})
});
};
I want to create the correct relashionship between the signed in user and the todos, more exactly I want to save the todos in the todos property of the UserSchema.
You should store a user reference within each todo item vs the other way around.
This is a link about One to Many doc references that may help you with modeling your DB.
https://docs.mongodb.com/manual/tutorial/model-referenced-one-to-many-relationships-between-documents/

Unable to query sub document mongoose

I've schema like this and i', trying to get the document from the array using _id. This is my first Mongo project that I'm working, please help me how can I achieve the. I basically want to retrieve the sub document corresponds to the id and update some data in that.
var PhoneSchema = new mongoose.Schema({
type: String,
number: String
});
var StudentSchema = new mongoose.Schema({
name: String,
dept: String,
phone: [PhoneSchema]
});
var Phone = mongoose.model('Phone',PhoneSchema);
var Student = mongoose.model('Student',StudentSchema);
I've tried the following ways, but none of them are working.
Method 1: When I tried the same in the console it is giving me the parent document along with the sub document that corresponds to the phoneId
Student.findOne({"phone._id":new mongoose.Schema.Types.ObjectId(phoneId) }, {'phone.$':1}, function(err, student) {
}
Method 2: As per the mongoose documentation to retrieve sub documents, in this case I'm getting exception saying phone is undefined
Student.phone.Id(phoneId);
I've fixed this by removing Schema from the below query
Student.findOne({"phone._id":new mongoose.Types.ObjectId(phoneId) }, {'phone.$':1}, function(err, student) {
}
i tried to solve your requirement. The following code did the job.
var PhoneSchema = new mongoose.Schema({
type: String,
number: String
});
var StudentSchema = new mongoose.Schema({
name: String,
dept: String,
phone: [PhoneSchema]
});
var Phone = mongoose.model('Phone',PhoneSchema);
var Student = mongoose.model('Student',StudentSchema);
var newPhone = new Phone({
type: 'ios', number: '9030204942'
});
var newStudent = new Student({
name:'Pankaj',
dept:'cse',
phone:newPhone
});
// newStudent.save(function(err, ph) {
// if (err) return console.error(err);
// });
Student.findOne({"phone._id":mongoose.Types.ObjectId('587e6409e06170ba1708dc21') },{_id:0,phone:1}, function(err, phone) {
if(err){
console.log(err)
}
console.log(phone);
});
Find the following screenshot with result

mongoose updating a field in a MongoDB not working

I have this code
var UserSchema = new Schema({
Username: {type: String, index: true},
Password: String,
Email: String,
Points: {type: Number, default: 0}
});
[...]
var User = db.model('User');
/*
* Function to save the points in the user's account
*/
function savePoints(name, points){
if(name != "unregistered user"){
User.find({Username: name}, function(err, users){
var oldPoints = users[0].Points;
var newPoints = oldPoints + points;
User.update({name: name}, { $inc: {Points: newPoints}}, function(err){
if(err){
console.log("some error happened when update");
}
else{
console.log("update successfull! with name = " + name);
User.find({Username: name}, function(err, users) {
console.log("updated : " + users[0].Points);
});
}
});
});
}
}
savePoints("Masiar", 666);
I would like to update my user (by finding it with its name) by
updating his/her points. I'm sure oldPoints and points contain a
value, but still my user keep being at zero points. The console prints
"update successful".
What am I doing wrong? Sorry for the stupid / noob question.
Masiar
It seems you are doing a few unstandard things:
Use findOne instead of find if you want to load just one user
Calling Model.update should be done to update records that you have not loaded
$inc is adding oldPoints, so the new value will be 2*oldPoints + newPoints
You are using name as the conditional query instead of Username
I would rewrite the code into something like this:
User.findOne({Username: name}, function(err, user){
if (err) { return next(err); }
user.Points += points;
user.save(function(err) {
if (err) { return next(err); }
});
});
follow my code guy
User.update({ username: "faibaa" },
{ $inc: { point: 200000 } }, function(err,data){
return res.send(data);
});