This question already has answers here:
Mongoose Unique index not working!
(35 answers)
Closed 6 years ago.
I am trying to sign up a new user via Angular app, but when I am registering a user with the same username, Mongo allows me to do this, so it does not reurn an error and afterwards I can see two users with same names in the db. But I do mark name field as unique.
part of api:
apiRoutes.post('/signup', function(req, res) {
if (!req.body.userId || !req.body.password) {
res.json({success: false, msg: 'Please pass name and password.'});
} else {
var newUser = new User({
name: req.body.name,
password: req.body.password,
wallet: req.body.wallet,
userPic: req.body.userPic
});
// save the user
newUser.save(function(err) {
if (err) {
return res.json({success: false, msg: 'Username already exists.'});
}
res.json({success: true, msg: 'Successful created new user.'});
});
}
});
model code:
// set up a mongoose model
var UserSchema = new Schema({
name: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
},
wallet: {
type: Number,
required: true
},
userPic: {
type: String,
required: true,
unique: true
}
});
And POST request code(login and password are taken from outside):
let newUser = {
password: password,
wallet: 0,
userPic: md5(login),
name: login
};
this.$http.post('http://127.0.0.1:8080/api' + '/signup', newUser);
try in your model:
name: {
type: String,
index:{unique: true},
required: true
}
Related
I am working in creating a todo list and one of the action I want users to do is delete all completed todos in one click. I have my models here, and the code I have, I have been reading trying to figure it out, but can't find it anywhere. Thanks in advance.
User Model
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
todos: [{
type: mongoose.Types.ObjectId,
ref: 'Todo'
}]
});
Todo model:
const TodoSchema = new mongoose.Schema({
creator: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User',
},
content: {
type: String,
required: true,
},
completed: {
type: Boolean,
default: false
},
});
This is what I have now. I get a "Cast to ObjectId failed for value true at path todos.
router.delete('/delete/completed', auth, async (req, res) => {
try {
const userTodos = await User.update(
{'_id':req.user.id},
{ $pull: { 'todos': { 'completed': true } } },
{ multi: true }
);
if (!userTodos) {
return res.status(400).send('Server error');
}
return res.json({ userTodos });
//return res.json({msg: 'All completed removed'})
} catch (err) {
console.error(err.message);
return res.status(404).json({ msg: 'Something went wrong, try again' });
}
});
If you are (as it seems from your code) using mongoose, you could use mongoose's populate feature:
const userTodos = await User.find(
{'_id':req.user.id}).populate('todos', {
match: {completed: true}
});
please note, however, that you'll need to delete both the documents in the todos collection, AND the todo reference in the user's todos array. You may consider to remove one side of the reference, see the pros and cons of two-way referencing here
I have the object array's ID and I want to update the info with information I already have on my backend.
My code deletes every array and creates a new one with the new info.
I want to access the array with the variable ID and then change it's values:
const ProdcutSchema = new mongoose.Schema({
name:{
type: String,
required: true
},
productDescription:{
type: String,
required: true
},
pricePerUnit:{
type: Number,
required: true
},
productAmmount:{
type:Number,
required: true
},
/*productImagePath:{
type:String,
required: true
}*/
});
const UserSchema = new mongoose.Schema({
name:{
type: String,
},
email:{
type: String,
},
password:{
type: String,
},
date:{
type: Date,
default: Date.now
},
products:[ProdcutSchema]
});
//Update products
router.put('/dashboard/:id', (req, res)=>{
const ID = req.params.id;
const {product_name, price_PerUnit, product_Description, product_Ammount} = req.body; //Get access to ajax data using body parser
if(!product_name || !price_PerUnit || !product_Description || !product_Ammount){
res.send('Please fill out all fields with valid content');
}else{
User.products.findOneAndUpdate(
{ _id : ID },
{ $set: { products: {
name :product_name,
productDescription : product_Description,
pricePerUnit : price_PerUnit,
productAmmount : product_Ammount
} } },
(err) => {
if (err) throw console.log('found errors');
console.log('no errors');
})
}
});
If you have ObjectId of that item you want to update, code should look like this:
User.products.findOneAndUpdate(
{ _id: ID, "products._id": <here goes id for an array element> },
{
$set: {
"products.$": {
name: product_name,
productDescription: product_Description,
pricePerUnit: price_PerUnit,
productAmmount: product_Ammount
}
}
},
err => {
if (err) throw console.log("found errors");
console.log("no errors");
}
);
Also u gotta be aware that u need to supply an specific ID of an array element for this kind of situation when you want to update subdocument.
I've tried almost everything splice, pop, shift, remove but I can't remove the user id which simple means downvote the post.
Here is my code:
// #type POST
// #route /api/question/upvote/:id
// #desc route for upvoting answers to questions
// #access PRIVATE
router.post('/upvote/:id', passport.authenticate('jwt', {session:false}), (req, res)=> {
Profile.findOne({user: req.user.id})
.then(profile => {
Question.findById(req.params.id)
.then(question => {
if(question.upvotes.filter(upvote => upvote.user.toString() === req.user.id.toString()).length > 0){
return res.status(400).json({noUpvote : 'User is downvoted the question'});
}
question.upvotes.unshift({user : req.user.id});
question.save()
.then(question => res.json(question))
.catch(err => console.log('Error on saving the upvote user id :' + err));
})
.catch(err => console.log('Error on getting the question : ' + err));
})
.catch(err => console.log('Error on finding the user : ' + err));
});
There are the three models in my application:
//Load the Person Model
const Person = require('../../models/Person');
//Load the Profile Model
const Profile = require('../../models/Profile');
//Load the Questions Model
const Question = require('../../models/Questions');
So the upvote is in question model.
The Person model contains the registration and login information.
The Profile model contains the Person details. The Question model contains question, answer, comment, and upvotes.
Here is the question model:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const QuestionSchema = new Schema({
user : {
type: Schema.Types.ObjectId,
ref: 'myPerson'
},
textone: {
type: String,
required: true
},
texttwo: {
type: String,
required: true
},
name:{
type: String
},
upvotes: [{
user : {
type: Schema.Types.ObjectId,
ref: 'myPerson'
}
}],
answers:[{
user : {
type: Schema.Types.ObjectId,
ref: 'myPerson'
},
answer: {
type: String,
required: true
},
name:{
type: String
},
date: {
type: Date,
default: Date.now
}
}],
comments: [{
user : {
type: Schema.Types.ObjectId,
ref: 'myPerson'
},
name:{
type: String
},
text: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
}],
date: {
type:Date,
default: Date.now
}
});
module.exports = Questions = mongoose.model("myQuestion", QuestionSchema);
you can remove the id using filter.
question.upvotes = question.upvotes.filter(upvote => upvote.user.toString() !== req.user.id.toString());
question.save();
add it inside the if condition if this is where you want to remove it.
Im trying to implement passsport on an old project and the scema's are set up to be nested for different things for example the name schema below is my sub schema.(There are more this is just for an example)
var nameSchema = new Schema(
{
_id: false,
"firstname" : {type: String, required: true},
"lastname" : {type: String, required: true}
});
// Schema setup
var schema = new Schema(
{
local :
{
name : nameSchema,
email : { type: String, required: true, trim: true, unique: true, select: true},
password : { type: String, required: true, trim: true, select: true},
regDate : { type: Date, select: false, createdAt: true},
alevel : { type: Number, min : 1, max : 5, default: 1, select: true },
}
});
But when I go to add this to my local strategy I get an error TypeError: Cannot set property 'firstname' of undefined How are nested json strategies implemented.
Currently what I have is:
passport.use('local-signup', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
aLevelField : 'aLevel',
namefield : {
firstnameField : 'firstname',
lastnameField : 'lastname'
},
passReqToCallback : true
},
function(req, email, password, done) {
process.nextTick(function() {
User.findOne({ 'local.email' : email }, function(err, user) {
if (err){
return done(err);
}
if (user){
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else {
var user = new User();
user.local.email = email;
user.local.password = password;
user.local.aLevel = req.body.aLevel;
user.local.name.firstname = req.body.firstname; // <-- error
user.local.name.lastname = req.body.lastname;
console.log('after define',user);
user.save(function(err){
if (err){
console.log(err)
throw err;
}
return done(null, user);
});
}
});
});
}));
Just incase anyone also comes across this and cant figure it out. When I called
user.local.name.firstname = req.body.firstname this from what i can assume was trying to access .name.firstname but because it was empty there was nothing to set .firstname too.
To fix it do:
user.local.name = {
firstname : req.body.firstname,
lastname : req.body.lastname
};
What is the best method to check if field value already exists.
This is my model:
// Set global
var moment = require('moment');
var _ = require('lodash');
// Create model
module.exports = function (orm, db) {
var Profile = db.define('profile',
// Field Properties
{
username: {type: 'text', required: true, unique: true},
name: {type: 'text', required: true},
email: {type: 'text', required: true},
password: {type: 'text', required: true},
birthday: {type: 'date', required: true},
gender: {type: 'enum', values: ["male", "female"], required: true},
join_date: {type: 'date'}
},
{
// Model hooks. Manual: https://github.com/dresende/node-orm2/wiki/Model-Hooks
hooks: {
beforeValidation: function() {
// Set join date to current date
this.join_date = new Date();
}
},
// Model Validations. Manual: https://github.com/dresende/node-orm2/wiki/Model-Validations
validations: {
username: [orm.enforce.security.username({length: 4}, 'Invalid username')],
email: [orm.enforce.patterns.email('Please enter a valid email')],
password: [orm.enforce.security.password('6', 'Invalid password')],
birthday: [orm.enforce.patterns.match(/\d{2}-\d{2}-\d{4}/, null, 'Invalid birthday')]
},
// Model methods. Extra functions and stuff
methods: {
}
});
};
And this is my register controller:
module.exports = function (req, res, next) {
// Get post params
var params = _.pick(req.body, 'formAction', 'username', 'password', 'email', 'confirm_password',
'birthday', 'gender', 'terms');
// If we try to register
if (params['formAction'] == 'register') {
// Manual validations
// Check if we agreed with the terms
if (params['terms'] != 1) {
res.send({error: 'You must agree to the terms of service'});
return false;
}
// Check if password was confirmed
if (params['password'] && params['password'] != params['confirm_password']) {
res.send({error: 'Please confirm your password'});
return false;
}
// Check if username already exists
// Try to register
req.models.profile.create({username: params['username'],
password: params['password'],
email: params['email'],
birthday: params['birthday'],
gender: params['gender'],
name: params['username']}, function (err, items) {
// Check to see if we have error
error = helpers.getError(err);
// Return error
if (error)
res.send({error: error});
});
}
// Show login form
else
res.sendfile(settings.path + '/public/register.html');
};
How can i check if username already exists in db? Now if i try to create i get DUP_KEY error from database.
Thanks,
Radu
Looks like adding a hook and using next() worked out
beforeCreate: function (next) {
obj = this;
Profile.exists({email: this.email}, function (err, exists) {
if (exists) {
return next(new Error("Email already exists"));
}
else
{
Profile.exists({username: obj.username}, function (err, exists) {
console.log(exists);
if (exists) {
return next(new Error("Username already exists"));
}
else
return next();
});
}
});
}