What im trying to do is create an app where users can post items and others can vote on the items similar to Reddit etc.
Problem i have is that when one user votes on an item posted by another user they get a forbidden message.
How i do i make it so that one user can modify the votes count of another users item.
This is the model for the Item
var ItemSchema = new Schema({
title: {
type: String,
default: 'NA',
required: 'Please fill Item title',
trim: true
},
link: {
type: String,
required: 'Please fill Item URL',
trim: true
},
details: {
type: String,
default: 'NA',
required: 'Please fill Item Details',
trim: true
},
votes: {
type: Number,
default: '0'
},
voters: [{
type: Schema.ObjectId,
ref: 'User'
}],
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
So one user should be able to increment the upvotes for another users Item.
Routes
// Items collection routes
app.route('/items').all(itemsPolicy.isAllowed)
.get(items.list)
.post(items.create);
app.route('/items/itemCount').all()
.get(items.countitems);
app.route('/items/itemCountToday').all()
.get(items.countitemsToday);
// Single item routes
app.route('/items/:itemId').all(itemsPolicy.isAllowed)
.get(items.read)
.put(items.update)
.delete(items.delete);
Upvote function
$scope.upVoteHome = function(item) {
item.votes++;
item.$update(function() {
//$location.path('items/' + item._id);
}, function(errorResponse) {
// rollback votes on fail also
$scope.error = errorResponse.data.message;
});
};
Button
<button ng-show="authentication.user" ng-click="upVoteHome(item)" type="button"
class="btn btn-danger vote-up-button"><i class="glyphicon glyphicon-arrow-up"></i> Hot</button>
add a 'put' permission in the routing policy
{
roles: ['user'],
allows: [{
resources: '/deals',
permissions: ['get', 'post', 'put']
}, {
resources: '/deals/:dealId',
permissions: ['get', 'put']
}]
}
Related
Good day all,
i'm trying to save image galleries where each image can have up to 5 tags associated with them. So in the Document the Gallery field is an array that has multiple values of which the Tag attribute which itself is an array of Tags.
I'm having issue saving an image where the user adds 2 or more tags for that picture. below this is what i have in my mongoose user schema
gallery : [{
origin : {type: String, trim: true, default: null},
uploadOn: {type: Date, Default: null},
title: { type: String, trim: true, default: null},
caption: { type: String, trim: true, default: null },
tag: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Imagetag', unique: true, sparse: true }],
imageLink: { type: String, trim: true }
}]
and this is my update script
var query = {username:'testUser'};
var options = { runValidators: true };
var toUpdate = {
$addToSet : {
gallery : {
origin : req.body.orgin,
uploadOn: new Date(),
title: req.body.title,
caption: req.body.caption,
tag: '59a5fea0382f1305841f0d86' // working
$addToSet: { tag: { $each: ['59a5fea0382f1305841f0d86', '59a5fea0382f1305841f0d88'] } } , // not working
$push: { tag: { $each: ['59a5fea0382f1305841f0d86', '59a5fea0382f1305841f0d88'] } } , // not working
imageLink: req.body.path
}
}
};
// proceed to update
var user = await User.findOneAndUpdate(query, toUpdate, options);
i have listed the different combination that i have tried without success. i do not want to have to make multiple calls to update the tags one by one for that same image.
I'm using the following model schema:
var AppointmentSchema = new Schema({
appointment_date: {type: Date},
created: {
type: Date,
default: Date.now
},
updated: {type: Date},
client: [{ type: Schema.Types.ObjectId, ref: 'User' }],
staff_id: [{ type: Schema.Types.ObjectId, ref: 'User' }],
cost:{
type: Number
},
jobDone:{
type: Boolean,
default: false
},
cancelled:{
type: Boolean,
default: false
}
});
Which clearly references the User model.
When I query I want to populate the client and staff data, but without some of the fields that they hold within that model.
So if the Users model is:
var UserSchema = new Schema({
firstName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your first name']
},
lastName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your last name']
},
displayName: {
type: String,
trim: true
}
});
I would only want to populate with firstName and email (and omit the rest) is that possible?
To return a few specific fields returned for the populated documents, you need to pass the usual field name syntax as the second argument to the populate method:
Appointment
.findOne({ cancelled: true })
.populate('client', 'firstName displayName') // only return the User's firstName and displayName
.exec(function (err, appointment) {
if (err) return handleError(err);
console.log('The client name is %s', appointment.client.firstName);
// prints "The client name is Aaron"
console.log('The client display name is %s', appointment.client.displayName);
// prints "The client display name is aarontest'
})
I am using meanjs and I would like to store some user data in a one to many relationship. My case is similar to the articles example but the articles will only ever be accessed through the user. I want the route to be something like
Users/:userId/articles
or
Users/me/articles
Question 1
Should I just stick with the articles model as it is or should I make articles a subdocument of user. e.g.
var UserSchema = new Schema({
firstName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your first name']
},
lastName: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your last name']
},
displayName: {
type: String,
trim: true
},
email: {
type: String,
trim: true,
default: '',
validate: [validateLocalStrategyProperty, 'Please fill in your email'],
match: [/.+\#.+\..+/, 'Please fill a valid email address']
},
username: {
type: String,
unique: 'testing error message',
required: 'Please fill in a username',
trim: true
},
articles: [articleModel.schema],
password: {
type: String,
default: '',
validate: [validateLocalStrategyPassword, 'Password should be longer']
},
salt: {
type: String
},
provider: {
type: String,
required: 'Provider is required'
},
providerData: {},
additionalProvidersData: {},
roles: {
type: [{
type: String,
enum: ['user', 'store', 'admin']
}],
default: ['user']
},
updated: {
type: Date
},
created: {
type: Date,
default: Date.now
},
/* For reset password */
resetPasswordToken: {
type: String
},
resetPasswordExpires: {
type: Date
}
});
Question 2 if I make it a subdocument can I still use the $resource function or do I have to make custom functions?
The maximum BSON document size is 16 megabytes. The maximum document size helps ensure that a single document cannot use excessive amount of RAM or, during transmission, excessive amount of bandwidth. To store documents larger than the maximum size, MongoDB provides the GridFS API.
I am getting a MongoDB error when trying to insert a subdocument. The subdocs already have unique _ids, but an error is being thrown for a different, non-unique field that I don't want unique.
The error in Angular is: "Assets.serial already exist". How can I make this field contain duplicate values, and what is causing the model to assume it should be unique?
Here is my Mongoose model:
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var AssetUrlSchema = new Schema({
name: {
type: String,
unique: false,
default: '',
trim: true
},
url: {
type: String,
unique: false,
default: 'http://placehold.it/75x75',
trim: true
},
}),
AssetSchema = new Schema({
serial: {
type: Number,
unique: false
},
urls: {
type: [AssetUrlSchema],
unique: false,
default: [
{ name: '', url: 'http://placehold.it/75x75' },
{ name: '', url: 'http://placehold.it/75x75' }
]
}
}),
/**
* Item Schema
*/
ItemSchema = new Schema({
name: {
type: String,
default: '',
required: 'Please enter name',
trim: true
},
assets: {
type: [AssetSchema],
default: [],
unique: false
},
property: {
type: Schema.ObjectId,
zd: 'Please select a property',
ref: 'Property'
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
});
mongoose.model('Item', ItemSchema);
And here is my 'save' method:
function(){
var i = 0, assets = [];
for (;i < 24;i++) {
assets.push({
serial: 1000+i,
urls: {
name: 'Asset Name ' + i,
url: 'http://placehold.it/75x75?'
}
});
}
item = new Items ({
name: 'FPO',
property: newPropId,
assets: assets
});
return item.$save(
function(response){ return response; },
function(errorResponse) {
$scope.error = errorResponse.data.message;
}
);
}
The first time I insert a document, it works fine. Any subsequent time, it fails with a 400 because the assets.serial field is not unique. However, I am specifically marking that field as unique:false.
The error in the mode console is:
{ [MongoError: insertDocument :: caused by :: 11000 E11000 duplicate key error index: mean-dev.items.$assets.serial_1 dup key: { : 1000 }]
name: 'MongoError',
code: 11000,
err: 'insertDocument :: caused by :: 11000 E11000 duplicate key error index: mean-dev.items.$assets.serial_1 dup key: { : 1000 }' }
POST /api/items 400 14.347 ms - 41
Mongoose doesn't remove existing indexes so you'll need to explicitly drop the index to get rid of it. In the shell:
> db.items.dropIndex('assets.serial_1')
This will happen if you initially define that field unique: true but then later remove that from the schema definition or change it to unique: false.
If you're using MongoAtlas, you can go to the collection -> click 'indexes' -> on the index you want to delete, click 'drop index'
If you are in a dev/prototype mode, simply deleting the actual collection (after changing the unique:true to false for instance), will reset everything and mongoose will allow your duplicates.
I'm working on a NodeJS+Sequelize+jade web-app. I have a table called box and another one called user. The user has a one-to-many relation with box. What I like to do is list and show in a jade-template all the box details, including the user who owns it.
First I created the tables using sequelize tools
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('User', {
name: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
password: {
type: DataTypes.STRING,
allowNull: false
},
dateOfBirth: DataTypes.DATE,
role: {
type: DataTypes.ENUM,
values: ['ADMIN', 'USER'],
defaultValue: 'USER'
}
},{
classMethods:{
associate: function(models) {
User.hasMany(models.Box);
}
})
return User;
};
The same to box:
module.exports = function(sequelize, DataTypes) {
var Box = sequelize.define('Box',{
boxTitle: {
type : DataTypes.STRING,
allowNull: false
},
lifetime: {
type : DataTypes.DATE,
allowNull : false
},
status: {
type: DataTypes.ENUM,
values: ['ACTIVE', 'NOTACTIVE'],
defaultValue: 'ACTIVE'
},
count: {
type: DataTypes.INTEGER,
allowNull : false
}
},{
classMethods:{
associate: function(models) {
Box.belongsTo(models.User);
}
});
return Box;
};
So, when I put some data in the database, I'm trying to print te box information:
each box in boxes
each user in box.users
tr
td= box.getDataValue('boxTitle')
td= user.getDataValue('name')
td= box.getDataValue('lifetime')
td= box.getDataValue('count')
td= box.getDataValue('status')
I did this so far, but I'm getting an error:
Cannot read property 'length' of undefined
I believe the program is not recognizing the association between those two tables, but I'm not sure.
Does anyone knows how can I solve this problem, or maybe to it in a different way?
I would be very grateful if you could help me.