0

I am creating user creation page using mongodb and node. After getting name, email and password, I tried to hash password and save then into mongodb. I could have followed the best practice by using async and await. However I wanted to understand Promise more. So, I tried the following, but at some point I got stuck. Here, used bcrypt for stroing password safely, the steps are 1) bcrypt.getSalt 2) bcrypt.hash 3) create user with new password 4) save it to mongodb. If you look at the following codes, the steps are implemented with those steps. But, when saving user into mongodb, user is out of scope. My question here is how to implement them in the right way with Promise. Could you give me some good example for it? I am beginner programmer, so just want to learn this from expert. so I came to post this.

router.post("/", (req, res, next) => {
  bcrypt
    .genSalt(10)
    .then(salt => {
      console.log(`Salt: ${salt}`);
      return bcrypt.hash(req.body.password, salt);
    })
    .then(hash => {
      console.log(`Hash: ${hash}`);
      return new User({
        name: req.body.name,
        email: req.body.email,
        password: hash
      });
    })
    .then(user => {
      console.log(`User: ${user}`);
      return User.findOne({ email: user.email }).exec();
    })
    .then(function(err, found_user) {
      if (err) {
        return next(err);
      }

      if (found_user) {
        console.log("found user");
      } else {
        user.save(function(err) {
          if (err) {
            return next(err);
          }
          res.redirect(user.url);
        });
      }
    })
    .catch(err => console.error(err.message));
});
Anna Lee
  • 909
  • 1
  • 17
  • 37
  • "*`.then(function(err, found_user) { if (err) { return next(err); }`*" is totally off. A promise never resolves with two values, and when the onfulfill callback is called there won't be an error. – Bergi Nov 05 '18 at 20:17

1 Answers1

1

Why do you need to pass new User? It is not an async operation in mongoose. It just creates a new instance of your model. You can just refactor your code into something shorter like this:

router.post("/", (req, res, next) =>
  User.findOne({ email: user.email }).exec().then(user => {
    if(user) {
      console.log("found user")
      next()
    } else {
      return bcrypt
        .genSalt(10)
        .then(salt => bcrypt.hash(req.body.password, salt))
        .then(hash => {
          var user = new User({
            name: req.body.name,
            email: req.body.email,
            password: hash
          });
          return user.save().exec()
      }).then(user => {
        // user is saved do whats next
        next()
      })
    }
  }).catch(err => console.error(err.message));
)
Akrion
  • 18,117
  • 1
  • 34
  • 54
  • Thank you so much for your comment. I have one more function returning Promise, User.findOne({ email: user.email }).exec(), before user.save, it needs to be checked whether new user already exists or not. so.. that function is needed. What would be good way to integrate it in the codes? – Anna Lee Nov 05 '18 at 19:25
  • Ok makes sense I updated the answer. You would then start with your check if the user exists first before you do anything else etc. – Akrion Nov 05 '18 at 19:34
  • Thank you so much, it works well. I will think about it deeply based on your codes. thank you again. – Anna Lee Nov 05 '18 at 21:00
  • Glad it helped you. You can mark this as the answer if it resolved your issue. – Akrion Nov 05 '18 at 21:24