title: How to embed bcrypt into mongose API call?
body: <h2>Setup</h2>
  
  <p>I am doing web site authorization, and want to embed best practices into it, while keeping code clean and readible. For now I have classic code like this:</p>
  
  <pre><code>let foundUser = await userModel.findOne({ email: recievedEmail });
  if(!foundUser)
      error("not authorized!");
  const isPasswordMatch = await bcrypt.compare(recievedPassword, foundUser.password);
  if(!isPasswordMatch)
      error("not authorized!");
  foundUser.update({ $set: { lastLogin: new Date() }, $push: { myEvents: authEvent } });
  foundUser.save();
  success("authorized OK!");
  </code></pre>
  
  <p>Meanwhile, I've asked a question on the <a href="https://stackoverflow.com/a/55304188/1976993">best mongoose command to perform auth</a>, and we've forged up the following "auth-check-and-update" command, in an "atomic" manner:</p>
  
  <pre><code>const foundUser = await userModel.findOneAndUpdate(
      { email: recievedEmail, password: recievedPassword },
      { $set: { lastLogin: new Date() }, $push: { myEvents: authEvent } }
  );
  if(foundUser)
      success("authorized OK!");
  else
      error("not authorized!");
  </code></pre>
  
  <p>Idea here is obvious - if a user <em>with matching email and password is found</em> then user is <em>considered as authorized</em>, and its <em>last login timestamp is updated</em> (simultaneously).</p>
  
  <hr>
  
  <h2>Problem</h2>
  
  <p>To combine best practices from the two above, I need somehow to embed <code>bcrypt.compare()</code> call inside <code>findOneAndUpdate()</code> call. That is tricky to do, because I cannot just "compare hashed passwords"; bcrypt just works differently from simple hashes (like sha or md5): <a href="https://stackoverflow.com/a/39198006/1976993">For security reasons it returns different hashes every time</a>. (Answers in the link explains "why and how").</p>
  
  <hr>
  
  <h2>Solution Attempt</h2>
  
  <p>I've looked into <a href="https://www.npmjs.com/package/mongoose-bcrypt" rel="nofollow noreferrer"><code>mongoose-bcrypt</code></a> package: it is utilizing <code>Schema.pre()</code> functionality:</p>
  
  <pre><code> schema.pre('update', preUpdate);
   schema.pre('findOneAndUpdate', preUpdate);
  </code></pre>
  
  <p>To get the idea, please, take a look at <a href="https://github.com/proswdev/mongoose-bcrypt/blob/master/index.js#L112-L143" rel="nofollow noreferrer"><code>mongoose-bcrypt\index.js</code></a>.
  You will see, that <code>preUpdate</code> affects only creating new user (..<code>andUpdate</code> part), but not actual checking (<code>findOne</code>.. part). So this plugin could fit for implementing "user registration" / "change password". But it can't work for authorization in the proposed way.</p>
  
  <hr>
  
  <h2>Question</h2>
  
  <p>How would you "combine" <code>bcrypt.compare()</code> and <code>userModel.findOneAndUpdate()</code> calls under such circumstances?</p>