Reputation:
I am having some difficulty using promises with mongoose for signing up a new user who is not already in the database. Here is my code:
exports.signup = (req) => {
const newUser = {
email: req.body.email,
password: req.body.password
};
let result = {};
return new Promise((resolve, reject) => {
UserModel.findOne({email: newUser.email}, (err, existingUser) => {
if (err) {
return reject(err)
} else {
if (existingUser) {
return reject()
} else {
result = newUser;
UserModel.create(result);
return resolve(result)
}
}
})
})
};
The incoming request values are coming in but the app breaks in the finOne collection.
Can anyone spot the error?
Many Thanks.
UPDATE:
if I omit the mongoose method:
exports.signup = (req) => {
const newUser = {
email: req.body.email,
password: req.body.password
};
return Promise.resolve(newUser);
};
Everything works, but of course nothing is added to the database. So, as nearly as I can fathom, it is related to my mongoose method.
Final Update:
I figured out what my error was but pandres95
beat me to the punch with the correct answer posted, so I gave him the points. But I will also offer my solution below explaining in detail where I screwed up in case others follwo same path.
Amazing how the folks with less than 10K in points are always the ones to come to the rescue. ;)
Upvotes: 0
Views: 163
Reputation:
Solution:
Make the same mistake enough times and eventually you learn. Initially I had this:
import UserModel from '../models/security/user.api.model';
And while correct, my model actually declared the UserModel explicitly as a constant for export, meaning I should have instead:
import { UserModel } from '../models/security/user.api.model';
Although challenging, I am having a ball improving the starter project react-redux-universal-hot-example
I am splitting up my website with a static webpage port and an api port for better performance, and I am using react-redux for state, and isomorphic/universal routing for search engine spiders crawling, which is important because SPA (Single Page Application websites) do not allow search engine crawling automatically.
Unfortunately, or not, the github project aforementioned does not offer a db example, so I had to figure it out on my own.
Here is the sample solution with schema, api actions (server controllers) using JavaScript promises:
user.api.model.js:
'use strict';
import mongoose from 'mongoose';
const UserSchema = new mongoose.Schema({
email: {type: String, required: '{PATH} is required!', index: {unique: true}},
password: {type: String, min: 7, max: 15}, required: '{PATH} is required!',
active: {type: Boolean, default: false},
.....
createdAt: { type: Date, default: Date.now() },
updatedAt: { type: Date, default: Date.now() }
});
export const UserModel = mongoose.model('User', UserSchema);
security.api.actions.js (controller) with promises:
'use strict';
import { UserModel } from '../../models/user/user.api.model';
.....
exports.signup = (req) => {
let result = {};
return new Promise((resolve, reject) => {
UserModel.findOne({ email: req.body.email}, (err, existingUser) => {
if (!existingUser) {
const newUser = new UserModel({
email: req.body.email,
password: req.body.password
......
});
newUser.save((err) => {
if (err) {
reject(err)
} else {
result = newUser;
}
});
}
if (err) reject(err);
else resolve(result);
})
});
};
auth.shared.reducer.js:
const LOAD = 'security/LOAD';
const LOAD_SUCCESS = 'security/LOAD_SUCCESS';
const LOAD_FAIL = 'security/LOAD_FAIL';
const LOGIN = 'security/LOGIN';
const LOGIN_SUCCESS = 'security/LOGIN_SUCCESS';
const LOGIN_FAIL = 'security/LOGIN_FAIL';
const LOGOUT = 'security/LOGOUT';
const LOGOUT_SUCCESS = 'security/LOGOUT_SUCCESS';
const LOGOUT_FAIL = 'security/LOGOUT_FAIL';
const SIGNUP = 'security/SIGNUP';
const SIGNUP_SUCCESS = 'security/SIGNUP_SUCCESS';
const SIGNUP_FAIL = 'security/SIGNUP_FAIL';
const initialState = {
loaded: false
};
export default function reducer(state = initialState, action = {}) {
switch (action.type) {
case LOAD:
return {
...state,
loading: true
};
case LOAD_SUCCESS:
return {
...state,
loading: false,
loaded: true,
user: action.result
};
case LOAD_FAIL:
return {
...state,
loading: false,
loaded: false,
error: action.error
};
case LOGIN:
return {
...state,
loggingIn: true
};
case LOGIN_SUCCESS:
return {
...state,
loggingIn: false,
user: action.result
};
case LOGIN_FAIL:
return {
...state,
loggingIn: false,
user: null,
loginError: action.error
};
case LOGOUT:
return {
...state,
loggingOut: true
};
case LOGOUT_SUCCESS:
return {
...state,
loggingOut: false,
user: null
};
case LOGOUT_FAIL:
return {
...state,
loggingOut: false,
logoutError: action.error
};
case SIGNUP:
return {
...state,
signingUp: true
};
case SIGNUP_SUCCESS:
return {
...state,
signingUp: false,
user: action.result
};
case SIGNUP_FAIL:
return {
...state,
signingUp: false,
user: null,
signUpError: action.error
};
default:
return state;
}
}
export function isLoaded(globalState) {
return globalState.auth && globalState.auth.loaded;
}
export function load() {
return {
types: [LOAD, LOAD_SUCCESS, LOAD_FAIL],
promise: (client) => client.get('/security/createUserSession')
};
}
export function login(name) {
return {
types: [LOGIN, LOGIN_SUCCESS, LOGIN_FAIL],
promise: (client) => client.post('/security/login', {
data: {
name
}
})
};
}
export function logout() {
return {
types: [LOGOUT, LOGOUT_SUCCESS, LOGOUT_FAIL],
promise: (client) => client.get('/security/logout')
};
}
export function signup(email, password) {
return {
types: [SIGNUP, SIGNUP_SUCCESS, SIGNUP_FAIL],
promise: (client) => client.post('/security/signup', {
data: {
email: email,
password: password
}
})
};
}
If you are a React coder or enthusiast, I recommend you check out that starter kit if you haven't already. It is bleeding edge, yet I am confident the technology employed will be standard in the not too distant future.
Upvotes: 1
Reputation: 183
There may be some issues:
res
). Which webserver library/framework are you using?return
as the exit statement, and not a sequence of inline conditionals. They may lead to unexpected results.result
variable can't be recommended in this situation, because:
Here is how I'd solve the same situation from the mongoose schema.
var userSchema = new Schema({
email: String,
password: String
});
userSchema.statics.signup = function (data) {
return new Promise((resolve, reject) => {
this.findOne({
email: data.email
}, (err, existingUser) => {
if(err) return reject(err);
if(existingUser) return reject();
return this.create(data, (err) => {
if(err) return reject(err);
return resolve(data);
});
});
});
};
return userSchema;
A complete solution (including some unit tests) can be found here
Upvotes: 1