Mongoose model not persisting object - mongodb

In a nutshell, I'm working on a math assessment app that takes your answers and stores them in a database and I'm having trouble adding more than one object to the backend. The Mongoose model is as such:
const mongoose = require('mongoose');
const Algebra1Schema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user'
},
answers: {
type: Object
},
date: {
type: Date,
default: Date.now
}
})
module.exports = algebra1 = mongoose.model('algebra1', Algebra1Schema)
Here is the route:
// Submit application/json parser
var jsonParser = bodyParser.json();
router.post('/', [jsonParser, auth], async (req, res) => {
try {
let newTest = new algebra1({
answers: req.body,
user: req.user.id
})
await newTest.save();
res.json(req.body);
} catch (err) {
console.error(err.message);
res.status(500).send('Server error');
}
})
module.exports = router;
Here is the update action that makes an axios POST request:
export const submit = (results, history) => async dispatch => {
try {
const config = {
headers: {
'Content-Type': 'application/json'
}
}
const res = await axios.post('/api/algebra1', results, config);
// dispatch({
// type: QuestionActionTypes.RESET
// })
dispatch(setAlert('You\;ve finished your assessment!', 'success'));
history.push('/results');
} catch (err) {
console.error(err.message);
// dispatch({
// type: PROFILE_ERROR,
// payload: { msg: err.response.statusText, status: err.response.status }
// })
}
}
I want to add a percentage item to the algebra1 model, that looks like this:
const Algebra1Schema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user'
},
answers: {
type: Object
},
**percent:{
type: Number**
date: {
type: Date,
default: Date.now
}
})
When I changed the route to have a percent Number added, the request goes to the database, but the answers object and percent Number aren't included. I tried updating the route to:
let newTest = new algebra1({
answers: req.body.answers,
percent: req.body.percent
user: req.user.id
})
I tried adding the following before the axios POST request:
const body = JSON.stringify({ results, percent });
and using body in place of results in the axios POST request, but the same result; nothing was persisted to the database except the user.
Any ideas as to what I'm doing wrong? I thought maybe the results object I'm sending in my action isn't correct, but when I only send the answers as req.body, it goes through and the database has the answers object.

Related

How to update a user profile which has a property which is a ref in MongooseJS?

I have a User schema which has reference to a profile schema.
const UserSchema = new Schema(
{
_id: mongoose.Schema.Types.ObjectId,
email: {
....email props...
},
password: {
...password props...
},
profile: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Profile",
}],
},
);
const Profile = new Schema({
_user: {
type: Schema.Types.ObjectId, ref: 'User'
},
'displayName': {
type: String,
default: ''
},
'interestedActivities': ['Ping-pong'], <---- This bad boy/girl is an array
'memberSince': { type: Date, default: Date.now }
}
)
I'd like to create a route which can update the User properties AND the Profile properties in one shot—with a caveat one of the properties on the Profile model is an array!!!
I tried this....
handler
.use(auth)
.put((req, res, next) => {
emailValidator(req, res, next, 'email');
},
async (req, res, next) => {
await connectDB()
const {
profileDisplayName,
profileEmail,
interestedActivities } = req.body;
const update = {
email: profileEmail,
'profile.$.displayName': profileDisplayName,
'profile.$.interestedActivities': interestedActivities
}
const filter = { _id: req.user.id };
const updatedUser = await User.findOneAndUpdate(filter, update, { new: true })
try {
console.log("updatedUser ", updatedUser);
if (updatedUser) {
return res.status(200).send({
updatedUser,
msg: `You have updated your profile, good job!`
});
}
} catch (error) {
errorHandler(error, res)
}
})
export default handler;
My response is:
Status Code: 500 Internal Server Error
Cast to ObjectId failed for value "[
{
id: 'ae925393-0935-45da-93cb-7db509aedf20',
name: 'interestedActivities',
value: []
}
]" (type Array) at path "profile.$"
Does anyone know how I could also afford for the property which is an array?
Thank you in advance!

Trying to post data to MongoDB, get status code 200 but fail to post data

I am a newbie to programming.
Now, I am working on a MERN stack project, trying to post data to my mongoDB database, but failed after many attempts.
Database:
There are 2 collections, 'items' and 'users' in the same database. The schemas are as follows:
Item Schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Create Schema
const ItemSchema = new Schema(
{
entryDate: {
type: Date,
required: true
},
leaveDate: {
type: Date,
required: true
}
},
{
collection: 'items'
}
);
module.exports = Item = mongoose.model('Item', ItemSchema);
User Schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Create Schema
const UserSchema = new Schema({
userName: {
type: String,
required: true
},
Password: {
type: String,
required: true
}
});
module.exports = User = mongoose.model('users', UserSchema);
Front-end:
handleClick = (e) => {
const API_URL = 'http://localhost:5000/api/users/';
this.setState({
startDate: this.handleStartDate(e.target.value),
endDate: this.handleEndDate(e.target.value)
});
const newDate = {
startDate: this.state.startDate,
endDate: this.state.endDate
}
const data = JSON.stringify(newDate);
axios({
method: 'post',
url: API_URL + 'addnew',
data: data,
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Access-Control-Allow-Origin': '*',
"Accept": "application/json"
}
})
.then(response => {
if (response.status === 200) {
console.log('The status code is : ' + response.status);
}
})
.catch(err => {
console.log('-------Failed to add new data. Error occurred.-------');
});
};
Backend:
// #route POST api/items
// #desc Create An Item
// #access Public
router.post('/addnew', function(req, res) {
const newItem = new Item({
entryDate: req.body.entryDate,
leaveDate: req.body.leaveDate
});
console.log(newItem);
// save model to database
newItem.save(function(err) {
if (err) {
res.json({
success: false,
message: 'failed to post data'
})
} else {
res.json({
success: true,
message: 'success to post data'
})
}
})
});
I have tested the backend API with Postman, the status code is 200, but returns the error message, shown below as in the screenshot:
Screenshot of Postman
I am not sure where I went wrong, my guess is that data of the schema 'Item' could not be saved into the collection 'items', but I have no clue what I should do.
I will be really appreciated for every little help. Thanks in advance!
Try to change like this
const Item = require('path/to/ItemSchemas');
// #route POST api/items
// #desc Create An Item
// #access Public
router.post('/addnew', function(req, res) {
const newItem = new Item({
entryDate: req.body.entryDate,
leaveDate: req.body.leaveDate
});
console.log(newItem);
// save model to database. Since newItem hasn't been added to the db, we used Item.save instead
Item.save(newItem, function(err) {
if (err) {
// save to db failed!
res.status(500).json({
success: false,
message: err
})
} else {
res.json({
success: true,
message: 'success to post data'
})
}
})
});

How create relationship between two collections

I'm creating server app using nodejs(express) and mongodb(mongoose). I must create relationships between Organization model and Users model. After creating an organization, I want to create a user that will apply to a specific organization. One user can apply to many organizations. How can I do this?
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
// UserShema
const UserSchema = Schema({
login: {
type: String,
require: true,
unique: true
},
password: {
type: String,
require: true
},
organization: {
ref: "Organization",
type: Schema.Types.ObjectId
}
});
// Organization Schema
const OrganizationSchema = Schema({
label: {
type: String
},
users: [{
type: Schema.Types.ObjectId,
ref: "Users"
}]
});
//For now I have simple route for creating an Organization.
// request:
// {
// "label": "testOrg"
// }
exports.createOrganization = async (req, res) => {
try {
const org = await new Organization(req.body);
await org.save();
} catch (error) {
return res.status(500).json({error})
}
}
//And I have this route for user registration
exports.signup = async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
};
const {login} = req.body;
try {
const checkUser = await Users.findOne({login});
if (!checkUser) {
const user = await new Users(req.body);
await user.save();
return res.status(200).json({ user });
} else {
return res.status(400).json({error: "User already exist"})
}
} catch (error) {
return res.status(500).json({error})
}
};
You could embed the organization id into a string into the user document
Like this {
name: "Name",
location: "CA",
organizations: [123456789, 234567890, ...]
}

MongoDB & Mongoose: unable to populate a user's posts with .populate()

I've searched this site for days looking through the many different but similar questions on this topic to no avail.
Here's what I'd like to happen. A user signs in and their posts are automatically linked to the users collection. Eventually I'd like to link posts to the profile it was posted to, but i"m not quite there yet. Here's what I've tried so far.
In the User Schema:
const UserSchema = new Schema({
posts: [{
type: Schema.Types.ObjectId,
ref: 'posts'
}],
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
...
});
module.exports = User = mongoose.model('users', UserSchema);
In the Post Schema:
const PostSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
text: {
type: String,
required: true
},
name: {
type: String
},
...
});
module.exports = Post = mongoose.model('posts', PostSchema);
In my users api, here's how I'm signing the user in and attempting to populate the user's posts:
const User = require('../../models/User');
router.post('/login', (req, res) => {
const { errors, isValid } = validateLoginInput(req.body);
// Check Validation
if (! isValid) {
return res.status(400).json(errors);
}
const email = req.body.email;
const password = req.body.password;
// Find user by email
User.findOne({ email })
.populate('posts')
.then(user => {
if (! user) {
errors.email = 'User not found';
return res.status(400).json(errors);
}
// Check password
bcrypt.compare(password, user.password).then(isMatch => {
if (isMatch) {
// User Matched
// Create JWT Payload
const payload = {
id: user.id,
firstName: user.firstName,
lastName: user.lastName,
name: user.firstName + ' ' + user.lastName,
avatar: user.avatar,
posts: user.posts
};
jwt.sign(
payload,
keys.secretOrKey,
{ expiresIn: 3600 }, (err, token) => {
res.json({
success: true,
token: 'Bearer ' + token,
payload
});
});
} else {
errors.password = 'Password is incorrect';
return res.status(400).json(errors);
}
});
});
});
In the posts api, here's how the post is being submitted:
router.post('/', passport.authenticate('jwt', { session: false }), (req, res) => {
const { errors, isValid } = validatePostInput(req.body);
if (! isValid) {
// Return errors with 400 status
return res.status(400).json(errors)
}
const newPost = new Post({
text: req.body.text,
name: req.body.name,
avatar: req.body.avatar,
user: req.user.id
});
newPost.save().then(post => res.json(post));
});
Currently, all I'm seeing is an empty array and no errors. I've been spinning my wheels on this one for a couple days now so any help would be appreciated. Thanks!
I think you forgot to save the _id of your new post to the User model so that the populate() can lookup the posts to populate:
newPost.save().then(post => {
User.update({ _id: req.user.id }, { $push: { posts: post._id }}, (err) => {
res.json(post));
});
});

MongoDb NodeJs RangeError: Maximum call stack size exceeded when pushing message

I'm learning how to create a MEAN app and I'm having a problem when I try to push a message into a messages array in my User Model.
I can create a new message and pass the user object but when trying to pass the message object into the user.messages array I get an error in the console 'RangeError: Maximum call stack size exceeded'.
I'll post my User and Message Models and the Message Route code.
Message Model
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
let User = require('./user');
let schema = new Schema({
content: {
type: String,
required: true
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
});
module.exports = mongoose.model('Message', schema);
User Model
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
let mongooseUniqueValidator = require('mongoose-unique-validator');
let schema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
password: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
messages: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Message'
}]
});
schema.plugin(mongooseUniqueValidator);
module.exports = mongoose.model('User', schema);
And my Route code
let express = require('express');
let router = express.Router();
let jwt = require('jsonwebtoken');
let User = require('../models/user');
let Message = require('../models/message');
router.get('/', function (req, res, next) {
Message.find()
.exec(function (err, messages) {
if (err) {
return res.status(500).json({
title: 'An error occurred',
error: err
});
}
res.status(200).json({
message: 'Success',
obj: messages
});
});
});
// Protect Routes
router.use('/', (req, res, next) => {
jwt.verify(req.query.token, 'secret', (err, decoded) => {
if (err) {
return res.status(401).json({
title: 'Not Authenticated',
error: err
});
}
next();
});
});
router.post('/', (req, res, next) => {
let decoded = jwt.decode(req.query.token);
User.findById(decoded.user._id, (err, user) => {
if (err) {
return res.status(500).json({
title: 'An error occurred',
error: err
});
}
let message = new Message({
content: req.body.content,
user: user
});
message.save((err, result) => {
if (err) {
return res.status(500).json({
title: 'An error occurred',
error: err
});
}
user.messages.push(result);
user.save();
res.status(201).json({
message: 'Saved message',
obj: result
});
});
});
});
module.exports = router;
I believe the problem comes form the post route
user.messages.push(result);
Thanks
You are using refs in your schemas so you should store the _id value rather than the whole object:
...
let message = new Message({
content: req.body.content,
user: user._id
})
...
...and:
user.messages.push(result._id)
I hope this helps solve your problem.