I am absolutely new to the MEAN stack, and I am using the MEAN.js(ver 0.4.2) generator for my project.
I am using the default users module and created a new module 'Topics' using the module generator. I have a basic role based login system using the users module where users can sign up and see/edit their profiles. In the profile, there is a reference to the topics module's mongoose model called 'Topics'.
topic.server.model.js looks like this(this is the schema for the topics) :
//Topic Schema
var TopicSchema = new Schema({
.......
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Topic', TopicSchema);
The content from this model can access the data from the users model. But the i cant get the items to show from the topics model, when i am referencing them from the users module.
My users model has this in the schema :
var UserSchema = new Schema({
......
interest: [{
type: Schema.Types.ObjectId,
ref: 'Topic'
}],
skills: [{
type: Schema.Types.ObjectId,
ref: 'Topic'
}]
});
mongoose.model('User', UserSchema);
I am trying to populate the data from topics using the following middleware :
exports.userByID = function (req, res, next, id) {
if (!mongoose.Types.ObjectId.isValid(id)) {
return res.status(400).send({
message: 'User is invalid'
});
}
User.findById(id, '-salt -password').populate('interest', 'name').populate('skills', 'name').exec(function (err, user) {
if (err) {
return next(err);
} else if (!user) {
return next(new Error('Failed to load user ' + id));
}
req.model = user;
next();
});
};
I would need a little guidance as to how do i get the data in front end to show, something like {{user.interest.name}}.
Edit
In the users.profile.server.controller, the json is not getting created from this :
exports.me = function (req, res, next) {
var id = req.user._id;
User.findOne({
_id: id
}).populate('interest', 'name').populate('skills', 'name').exec(function(err, userData) {
if (err) return next(err);
if (!userData) return next(new Error('Failed to load User ' + id));
res.json(userData || null);
next();
});
};
Getting the following error in the terminal :
GET /api/users/me 400 22.173 ms - -
Error: Can't set headers after they are sent.
Related
I have an array (bookedby) in a Mongoose model defined like this:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var BarSchema = new Schema({
date: {
type: Date,
required: true
},
barid: {
type: String,
required: true
},
bookedby: {
type: [String],
required: true
},
});
module.exports = mongoose.model('Bar', BarSchema);
I update it with following function, called by a nodejs express router:
const Bars = require("../../models/bars");
const { getToday } = require('../../utils');
module.exports = function(req, res) {
const { barid } = req.body;
const { username } = req.user;
const date = getToday();
if( !barid ) return res.json({ success: false, error: 'Please specify parameter \'barid\'.'})
Bars.findOne({ barid, date }, function (err, bar) {
if (err) return next(err);
if (!bar || bar.bookedby.indexOf(username) === -1) return res.json({ error: `Bar is not booked yet.` });
// Someone booked the bar
const index = bar.bookedby.indexOf(username);
bar.bookedby.splice(index, 1);
bar.save(err => {
if (err) res.json({ error: `Error saving booking.` });
else res.json({ success: true });
});
});
};
Everything works fine, except when I remove the last item from the bookedby array. Then the save() function doesn't update the database. The last item remains there. I guess it has something to do with mongodb optimizing empty arrays, but how can I solve this?
According to the Mongoose FAQ:
http://mongoosejs.com/docs/faq.html
For version >= 3.2.0 you should use the array.set() syntax:
doc.array.set(3, 'changed');
doc.save();
If you are running a version less than 3.2.0, you must mark the array modified before saving:
doc.array[3] = 'changed';
doc.markModified('array');
doc.save();
I am building an app with mongoDB and NodeJS with an Angular front end. I currently have users creating listings and then other users responding with bids within those listings, but want to include data of those responders. I am having a hard time including that user data in the bid create function and not sure why its not pulling.
Here is the listing schema
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var Bid = require('./bid');
var ListingSchema = new Schema({
topic: String,
description: String,
budget: String,
location: String,
req1: String,
req2: String,
req3: String,
created: String,
dateReq: String,
uid: String,
bids: [Bid.schema]
})
This is how I currently create new listings
function create(req, res) {
db.User.findById(req.user, function (err, user) {
if (err) {console.log(err);}
var newListing = new db.Listing(req.body);
newListing.uid = user._id
newListing.save(function (err, savedListing) {
if (err) {
res.status(500).json({ error: err.message });
} else {
user.listings.push(newListing);
user.save();
res.json(savedListing);
}
});
});
};
This is for new bids. For some reason, the db.User information is not getting pulled and my console log shows a blank object. (Yes I commented it out)
function create(req, res) {
// db.User.findById(req.user, function (err, user) {
// console.log(req.user);
// if (err) {console.log(err);}
db.Listing.findById(req.params.listingId, function(err, foundListing) {
var newBid = new db.Bid(req.body); // add data validation later
// newBid.uid = user._id
foundListing.bids.push(newBid);
foundListing.save(function(err, savedBid) {
res.json(newBid);
});
});
});
};
try using user_id as a Object reference and populate it when needed your schema should be somewhat like this
var ListingSchema = new Schema({ topic: String,description: String, budget: String, location: String, req1: String, req2: String, req3: String, created: String, dateReq: String,//THIS CREATES A REFERENCE TO THE SCHEMA USER AND TO USE THIS YOU CAN POPULATE IT.. uid: {type:Schema.type.ObjectId,ref:User}, bids: [Bid.schema]})
I have a User model and each user document has name field which is String and friends field which is an array of integers which holds id's of other users who this user is friends with.
Whenever I want to create a new user document with one id already in friends array, I have to three steps: 1. create new user with specific name; 2. save this user; 3. update this user's friends field by adding new friend id to the array.
I was wondering if there is another, more efficient way of achieving the same result. Here is my code so far:
var User = mongoose.model('User',{
friends: {
type: [Number],
required: false
},
name: String
});
//cretae new user document
var user = new User ({
name: name
});
user.save(function(err){
if(err){
console.log("something went wrog, read below");
console.log(err);
}else{
User.update({'name': name}, {
$addToSet: { 'friends': newFriendId}
},function(err, count) {
if(err){
console.log(err);
}else{
console.log(count);
}
});
}
});
var User = mongoose.model('User',{
friends: {
type: [Number],
required: false
},
name: String
});
//cretae new user document
var user = new User ({
name: name,
friends : [newFriendId]
});
user.save(function(err){
if(err){
console.log("something went wrog, read below");
console.log(err);
}else{
}
});
I would like to ask if there is anyone getting the same response on JSON format:
Objectdata: "User is not authorized"headers: (name) {status: 403statusText: "Forbidden"
Scenario:
User A post a product and add comment on the product.
Result: Successful.
User B comment on the same product:
Result: User is not authorized.
The code I'm using to update the product comment is here:
applicationname/`
// Add comment to Product
$scope.comment = function(){
// console.log("name: ",$scope.user);
// console.log("textarea: ",this.commentarea);
var comment = {
name: $scope.product.user.displayName,
text: this.commentarea
};
$scope.product.comments.push(comment);
$scope.product.$update(function() {
console.log('success update');
}, function(errorResponse) {
console.log('success error', errorResponse);
});
};
This is the server side.
'use strict';
/**
* Module dependencies.
*/
var init = require('./config/init')(),
config = require('./config/config'),
mongoose = require('mongoose'),
chalk = require('chalk');
/**
* Main application entry file.
* Please note that the order of loading is important.
*/
// Bootstrap db connection
var db = mongoose.connect(config.db, function(err) {
if (err) {
console.error(chalk.red('Could not connect to MongoDB!'));
console.log(chalk.red(err));
}
});
// Init the express application
var app = require('./config/express')(db);
// Bootstrap passport config
require('./config/passport')();
// Start the app by listening on <port>
app.listen(config.port);
// Expose app
exports = module.exports = app;
// Logging initialization
console.log('MEAN.JS application started on port ' + config.port);
If your Products schema looks like this:
var ProductSchema = new Schema({
created: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true,
required: 'Title cannot be blank'
},
comments: [{
type: String,
default: '',
trim: true
}]
});
And you have restricted your products route in your app/routes/products.server.routes.js file like so:
app.route('/products/:productId')
.get(products.read)
.put(users.requiresLogin, products.hasAuthorization, products.update)
.delete(users.requiresLogin, products.hasAuthorization, products.delete);
Then a non-authorized user cannot add a comment because they can't update the Product record.
You probably want to create a separate CommentsSchema and use the Mongoose ObjectId type to create a one-to-many relationship with the product:
var CommentSchema = new Schema({
product: ObjectId,
content: {
type: String,
default: '',
trim: true,
required: 'Content cannot be blank'
},
})
That will preserve the security of your product and allow non-authorized users to comment, but would require you to do slightly more complex queries to get your comments in your product view.
I am experimenting with the MEAN stack, specifically with MEAN.js.
While everything is pretty well explained in the documentation, it seems that the simple task to associate an entity (or Model) with another isn't explained in the documentation or the examples.
For example, it is easy to generate a crud for Ideas and one for Polls. But what if I have to link "polls" to an "idea", in a one-to-many relation?
I assume I would do something that resembles to this in polls.client.controller.js:
// Create new Poll
$scope.create = function() {
// Create new Poll object
var poll = new Polls ({
ideaId: this.idea.ideaId,//here I associate a poll with an Idea
vote1: this.vote1,
vote2: this.vote2,
vote3: this.vote3,
vote4: this.vote4,
vote5: this.vote5
});
// Redirect after save
poll.$save(function(response) {
$location.path('polls/' + response._id);
// Clear form fields
$scope.name = '';
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
But when the angular model is pushed to Express.js backend, I don't see any trace in the request about the Idea, the only thing I get is the Poll.
/**
* Create a Poll
*/
exports.create = function(req, res) {
var poll = new Poll(req.body);
poll.user = req.user;
//poll.ideaId = req.ideaId;//undefined
poll.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(poll);
}
});
};
Here is my Mongoose Model:
'use strict';
/**
* Module dependencies.
*/
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
/**
* Poll Schema
*/
var PollSchema = new Schema({
vote1: {
type: Number
},
vote2: {
type: Number
},
vote3: {
type: Number
},
vote4: {
type: Number
},
vote5: {
type: Number
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
},
idea: {
type: Schema.ObjectId,
ref: 'Idea'
}
});
mongoose.model('Poll', PollSchema);
I am sure that there is something I did wrong, but any explanation (or link) on how to perform this task that goes beyond this particular error or setup of mine would be appreciated.
The solution I found (I am not sure if it is the correct solution or a workaround) is to populate the .idea field of a poll with its corresponding ._id:
var poll = new Polls ({
idea: this.idea._id,
vote1: 5,
vote2: 3,
vote3: 3,
vote4: 1,
vote5: 2
});
At this point, when I get to express, poll.idea has the correct association.