Referencing Other Models when Saving Data Express/Mongoose - javascript

I have a simple express app where users can log in and post pictures of mountains. I'm having an issue saving the posts the users add. Specifically, the user id that is referenced from another schema(user schema). When I submit the form, I get an undefined error on the "._id" and I'm not sure how to go about fixing it.
Below are my model schemas.
const userSchema = new Schema({
name: String,
email: String,
username: String,
password: String,
});
const canyonSchema = new Schema({
canyon: String,
image: String,
description: String,
cost: Number,
createdAt: { type: Date, default: Date.now },
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
}
});
const Canyon = mongoose.model("Canyon", canyonSchema);
module.exports = Canyon;
const User = mongoose.model('User', userSchema);
module.exports = User
Here is the logic that is supposed to save the information to mongo. When I run, I get a "._id undefined". Any help.
const User = require('../models/user');
const Canyon = require('../models/Canyon');
router.post("/add", , function(req, res){
if(req.body.canyon &&
rea.body.image &&
req.body.description){
const newCanyon = {
canyon: req.body.canyon,
image: req.body.image,
description: req.body.description,
author: {
id: req.user._id,
}, username: req.user.username
};
Canyon.create(newCanyon, function(error, canyon){
if(error){
return next(error)
} else {
req.session.userId = user._id;
return res.redirect('/profile')
}
});
} else {
const err = new Error('All fields required.');
err.status = 400;
return next(err);
}
});

In your model schema, instead of
const canyonSchema = new Schema({
canyon: String,
image: String,
description: String,
cost: Number,
createdAt: { type: Date, default: Date.now },
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
}
});
Make the author itself the reference:
const canyonSchema = new Schema({
canyon: String,
image: String,
description: String,
cost: Number,
createdAt: { type: Date, default: Date.now },
author: { type: mongoose.Schema.ObjectId, ref: 'User', index: true },
});
To create a canyon object,
const newCanyon = {
canyon: req.body.canyon,
image: req.body.image,
description: req.body.description,
author: req.user._id
};
To get the user information embedded in the canyon object when query on canyons, just populate the author in the query,
Canyon.findById(id).populate('author').exec()

Related

How can i create a module for a course website using mongoDB and node.js

/I want to create a module section for a course website for which I will need a lesson schema as well so How can I design lesson schema , module schema , and course schema so they
work just how they are needed to workCurrently I am doing this/
import mongoose from 'mongoose'
const LessonSchema = new mongoose.Schema({
title: String,
content: String,
resource_url: String
})
const ModuleSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
lessons: [LessonSchema]
})
export const Module = mongoose.model('Module', ModuleSchema);
const CourseSchema = new mongoose.Schema({
name: {
type: String,
trim: true,
required: 'Name is required'
},
price: {
type: String,
trim: true,
required: true
},
image: {
data: Buffer,
contentType: String
},
intro: {
type: String,
required :true
},
description: {
type: String,
trim: true
},
category: {
type: String,
required: 'Category is required'
},
updated: Date,
created: {
type: Date,
default: Date.now
},
instructor: {type: mongoose.Schema.ObjectId, ref: 'User'},
published: {
type: Boolean,
default: false
},
modules: [ModuleSchema]
})
export default mongoose.model('Course', CourseSchema)
Above was the schema and this is logic
const newLesson = async (req, res) => {
try {
let lesson = req.body.lesson
let course = await Course.find({modules: {_id: req.params.moduleId}})
console.log(course)
} catch (err) {
return res.status(400).json({
error: errorHandler.getErrorMessage(err)
})
}
}
const newModule = async (req, res) => {
try {
let lesson = req.body.lesson
let result = await Course.findByIdAndUpdate(req.course._id, {$push: {modules: {name: req.body.name, lessons: lesson}}, updated: Date.now()}, {new: true})
.populate('instructor', '_id name')
.exec()
res.json(result)
} catch (err) {
return res.status(400).json({
error: errorHandler.getErrorMessage(err)
})
}
}
**I have been brainstorming this from a while and cant get through it do you know how can I shape the schema and logic so that I can push lessons in module and then module in course schema ? **

findOneReplace replacment issue

I want to find a document in my db and replace it with a document that has a new name and new key.
Here is my Schema
const Schema = mongoose.Schema;
const vampireSchema = new Schema({
name: { type: String, required: true },
title: String,
hair_color: {type: String, default: "blonde" },
eye_color: String,
dob: Date,
loves: [String],
location: String,
gender: String,
victims: {type: Number, min: 0}
});
const Vampire = mongoose.model("Vampire", vampireSchema);
module.exports = Vampire;
Here is my executable code
Vampire.findOneAndReplace( { name: "Claudia" }, { name: "Eve", portrayed_by: "Tilda Swinton" }, (err, vamp) => {
if(err){
console.log(err)
}
else{
console.log(vamp)
}
db.close()
})
There are two issues that I can see.
First, you should pass null as the third argument in your findOneAndReplace call. This will set the options to null and should get your code running. This is in my opinion a strange behavior of mongoose.
Vampire.findOneAndReplace(
{ name: "Claudia" },
{ name: "Eve", portrayed_by: "Tilda Swinton" },
null,
(err, vamp) =>
{
if(err){
console.log(err)
}
else{
console.log(vamp)
}
db.close()
})
Secondly, I would recommend adding the portrayed_by to the schema, otherwise, that field will not be in the newly created document. Therefore, I would adjust your schema that way:
const vampireSchema = new Schema({
name: { type: String, required: true },
title: String,
hair_color: {type: String, default: "blonde" },
eye_color: String,
dob: Date,
loves: [String],
location: String,
gender: String,
victims: {type: Number, min: 0},
portrayed_by: String
});

Mongoose pushing only ObjectID, not the whole document

I have a recipe blog site, where every single recipe have comments. Every comments saving into the comments collection, but when i push the comments to the right recipe, than only saving the ObjectID. Here is my code:
Recipe model
const { Double } = require('bson');
const mongoose = require('mongoose');
const recipeSchema = new mongoose.Schema({
name: {
type: String,
required: 'This field is required.'
},
description: {
type: String,
required: 'This field is required.'
},
quantity: {
type: Array,
required: 'This field is required.'
},
ingredients: {
type: Array,
required: 'This field is required.'
},
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Comment'
}
],
recipe_id: {
type: String,
}
});
recipeSchema.index({ name: 'text', description: 'text' });
const Recipe = module.exports = mongoose.model('Recipe', recipeSchema);
Comment Model
const commentSchema = new mongoose.Schema({
username: {
type: String,
required: 'This field is required.'
},
comment: {
type: String,
required: 'This field is required.'
},
recipe_id: {
type: String
}
});
Routes
router.get('/', recipeController.homepage);
router.get('/recipe/:id', recipeController.exploreRecipe );
router.get('/categories/:id', recipeController.exploreCategoriesById);
router.get('/categories', recipeController.exploreCategories);
router.get('/submit-recipe', recipeController.submitRecipe);
router.post('/submit-recipe', recipeController.submitRecipeOnPost);
router.post('/recipe/:id/comments', recipeController.CommentRecipeOnPost);
Controller
module.exports.CommentRecipeOnPost = async(req, res) => {
const comment = new Comment({
username: req.body.username,
comment: req.body.comment
});
comment.save((err, result) => {
if (err){
console.log(err)
}else {
Recipe.findById(req.params.id, (err, post) =>{
if(err){
console.log(err);
}else{
post.comments.push(result);
post.save();
console.log('====comments=====')
console.log(post.comments);
res.redirect('/');
}
})
}
})
}
I tried with populate and another methods, but no one worked, after a lots of hour programming i done with these, that i can save only the ObjectId-s.
This's because you define comments at recipe schema as an ObjectId and that's right, if you want to get full comment parameters you will populate the record
const recipe = await Recipe.findOne({ _id: "recordId"}).populate("posts")
this will return all comments details
{ name: "Fitness recipe", description: "Fitness recipe to loss 10kg in 10 days only", comments: [ {_id: "recordId", username: "Smith June", comment: "That's awesome"}]}
if you need to save the whole document as an array of objects, not just the id so you can make schema like that
const recipeSchema = new mongoose.Schema({
name: {
type: String,
required: 'This field is required.'
},
description: {
type: String,
required: 'This field is required.'
},
quantity: {
type: Array,
required: 'This field is required.'
},
ingredients: {
type: Array,
required: 'This field is required.'
},
comments: [
{ username: String, comment: String }
],
recipe_id: {
type: String,
}
})
and in this case, you won't have any relations, you can list recipe comments easily.

how to populate users object with field

These the response for user that Im getting from get request to profile API
"user": "5cc3a4e8d37a7259b45c97fe"
What I'm looking for instead is
"user":{
"_id": "5cc3a4e8d37a7259b45c97fe",
"name":"Jhon Doe",
}
Here is my code:
Profile.findOne({
user: req.user.id
})
.populate('user',['name']) // I added this line to populate user object with name
.then(profile=>{
if(!profile){
errors.noprofile = 'There is no profile for this user'
return res.status(404).json(errors);
}
res.json(profile)
})
.catch(err => res.status(404).json(err));
However, Im getting these error:
{
"message": "Schema hasn't been registered for model \"users\".\nUse mongoose.model(name, schema)",
"name": "MissingSchemaError"
}
What am I missing
Profile Schema
const ProfileSchema = new Schema({
user:{
type: Schema.Types.ObjectId,
ref: 'users'
},
handle: {
type: String,
required: true,
max: 40
},
company: {
type: String
},
website: {
type: String,
}
})
Here is how my Users schema looks like
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Create Schema
const UserSchema = new Schema({
name:{
type: String,
required: true,
},
email:{
type: String,
required: true,
},
password:{
type: String,
required: true,
},
avator:{
type: String,
},
date:{
type: Date,
default: Date.now,
}
});
module.exports = User = mongoose.model('Users', UserSchema)
Schema that you are referencing in Profile schema is users, but you have saved your user schema as Users. So I would say that you need to update your Profile schema:
const ProfileSchema = new Schema({
user:{
type: Schema.Types.ObjectId,
ref: 'Users'
},
handle: {
type: String,
required: true,
max: 40
},
company: {
type: String
},
website: {
type: String,
}
})
Name under which is saved your User schema can be found in this line
module.exports = User = mongoose.model('Users', UserSchema)
The error says you don't have Schema for Users. You reference it from Profile Schema, but you don't have it. It can be this way:
const Users = new Schema({
name: String
})

Saving an entry doesn't add the ref to my other document?

I have a ProfileSchema that I want to keep track of posts that have been posted. When I save a new Post it has a Profile_id but when I fetch the profile entry the posts array is empty. How does this work?
Profile Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ProfileSchema = new mongoose.Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
handle: {
type: String,
required: true,
max: 40
},
posts: [
{
type: Schema.Types.ObjectId,
ref: 'posts'
}
],date:{
type: Date,
default: Date.now
}
})
module.exports = Profile = mongoose.model('profile', ProfileSchema);
Post Schema
const PostSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
profile: {
type: Schema.Types.ObjectId,
ref: 'profile'
},
title: {
type: String,
required: true,
max: 40
},
body: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
})
module.exports = Profile = mongoose.model('posts', PostSchema)
how I save it
router.post('/', passport.authenticate('jwt', {session: false}), (req,res) => {
const newPost = new Post({
title: req.body.title,
body: req.body.body,
img: req.body.img,
user: req.user._id,
profile: req.body.profile_id
});
newPost.save().then(post => res.json(post));
})
I'm a bit confused the mongoose documentation uses syntax I'm not familiar with or haven't learned their way yet. my user populates when I fetch for the profile data but the posts array is blank when I populate it.

Categories