Mongoose findOne 查询返回旧数据,是否发生了一些缓存?

use*_*520 5 mongoose mongodb node.js express

我有一个使用一些属性创建的用户模型,这些属性稍后在用户激活后被删除。我注意到这些属性在用户发起忘记密码请求后重新出现。

当我单步执行代码(它是一个快速应用程序)时,我在忘记密码控制器中有一个 User.findOne 请求,该请求返回仍然具有已删除属性的用户文档,因此当我保存密码重置令牌。

function forgotPassword(req, res, next) {
  const username = req.body.username;

  // Generate token
  const token = uuid.v4();

  // Find the user
  User.findOne({ username: username }, function(err, user) {
    if (err) {
      return next(err);
    }
    // At this stage user also has the properties that 
    // were previously deleted when I inspect it
    user.resetToken = token;
    user.save(function(err, savedUser, numAffected) { 
      // So resetToken gets saved but also the previously deleted properties
      ...
    });
Run Code Online (Sandbox Code Playgroud)

我在数据库中验证了它们在用户激活时被删除,然后在忘记密码请求后重新出现。

Mongoose 对 findOne 请求是否有某种缓存?

我浏览了 Mongoose github issues 并没有发现任何东西。Mongoose findOne在幕后使用mquery ,但我看不到缓存层。

如何让 Mongoose 使用数据库中的实时数据?

更新了最小的例子:

[更新:我没有在最小示例中添加任何快速路线,但事件顺序本质上是相同的,尽管在实际应用程序中数据库调用分布在几个不同的快速路线上]

包.json:

{
  "name": "minimal-mongoose-findone-old-data-issue",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "chance": "^1.0.11",
    "mongoose": "^4.12.4",
    "uuid": "^3.1.0"
  }
}
Run Code Online (Sandbox Code Playgroud)

索引.js:

const mongoose = require('mongoose');  
const uuid = require('uuid');
const chance = new(require('chance'));

const dbPort = process.env.DBPORT;
const dbName = 'minimal-mongoose-findone-old-data-issue';

const mongoUrl = `mongodb://localhost:${dbPort}/${dbName}`;
mongoose.connect(mongoUrl, { user: '', pass: '' });
mongoose.set("debug",true);

const UserSchema = new mongoose.Schema({
  username: {
    type: String,
    unique: true
  },
  activationToken: {
    type: String,
    default: uuid.v4()
  },
  active: {
    type: Boolean,
    default: false
  },
  passwordToken: {
    type: String
  }
}, { timestamps: true });

const User = mongoose.model('User', UserSchema);

// Create user
const username = chance.first();
const user = new User();
user.username = username;
user.save(function(err, savedUser) {
  if (err) { throw err };
  console.log(`STEP 1: user created: ${JSON.stringify(savedUser, 0, 2)}`);

  // Activate user
  User.findOne({
    activationToken: savedUser.activationToken
  }, function(err, foundUser) {
    if (err) { throw err };
    console.log(`STEP 2: user found: ${JSON.stringify(foundUser, 0, 2)}`);
    foundUser.active = true;
    foundUser.activationToken = undefined;
    foundUser.save(function(err, activatedUser, numAffected) {
      if (err) { throw err };
      console.log(`STEP 3: user activated: ${JSON.stringify(activatedUser, 0, 2)}`);

      // Reset password
      User.findOne({
        username: username,
      }, function(err, resetPasswordUser) {
        if (err) { throw err };
        console.log(`STEP 4: user found for password reset: ${JSON.stringify(resetPasswordUser, 0, 2)}`);
        // Password reset logic here etc...
        // The problem is that since the second findOne call returns old data, 
        // the activationToken gets saved back to the database when I save resetPasswordUser
        process.exit();
      });
    });
  });
});
Run Code Online (Sandbox Code Playgroud)

在第3步中,console.log输出没有activationToken

在步骤 4 中,activationToken 又回到了 console.log 输出中

运行节点 index.js 的输出:[使用 mongo 调试输出更新]

Mongoose: users.insert({ updatedAt: new Date("Wed, 25 Oct 2017 08:02:48 GMT"), createdAt: new Date("Wed, 25 Oct 2017 08:02:48 GMT"), username: 'Hannah', _id: ObjectId("59f045287a2de871d0fbce14"), active: false, activationToken: 'c9048f36-02c7-4a0f-8e2c-abf5cb9120fe', __v: 0 })
STEP 1: user created: {
  "__v": 0,
  "updatedAt": "2017-10-25T08:02:48.107Z",
  "createdAt": "2017-10-25T08:02:48.107Z",
  "username": "Hannah",
  "_id": "59f045287a2de871d0fbce14",
  "active": false,
  "activationToken": "c9048f36-02c7-4a0f-8e2c-abf5cb9120fe"
}
Mongoose: users.findOne({ activationToken: 'c9048f36-02c7-4a0f-8e2c-abf5cb9120fe' }, { fields: {} })
STEP 2: user found: {
  "_id": "59f045287a2de871d0fbce14",
  "updatedAt": "2017-10-25T08:02:48.107Z",
  "createdAt": "2017-10-25T08:02:48.107Z",
  "username": "Hannah",
  "__v": 0,
  "active": false,
  "activationToken": "c9048f36-02c7-4a0f-8e2c-abf5cb9120fe"
}
Mongoose: users.update({ _id: ObjectId("59f045287a2de871d0fbce14") }, { '$unset': { activationToken: 1 }, '$set': { active: true, updatedAt: new Date("Wed, 25 Oct 2017 08:02:48 GMT") } })
STEP 3: user activated: {
  "_id": "59f045287a2de871d0fbce14",
  "updatedAt": "2017-10-25T08:02:48.153Z",
  "createdAt": "2017-10-25T08:02:48.107Z",
  "username": "Hannah",
  "__v": 0,
  "active": true
}
Mongoose: users.findOne({ username: 'Hannah' }, { fields: {} })
STEP 4: user found for password reset: {
  "_id": "59f045287a2de871d0fbce14",
  "updatedAt": "2017-10-25T08:02:48.153Z",
  "createdAt": "2017-10-25T08:02:48.107Z",
  "username": "Hannah",
  "__v": 0,
  "active": true,
  "activationToken": "c9048f36-02c7-4a0f-8e2c-abf5cb9120fe"
}
Run Code Online (Sandbox Code Playgroud)

运行index.js后在mongo shell中:

MongoDB shell version: 3.2.4
connecting to: test
> use minimal-mongoose-findone-old-data-issue
switched to db minimal-mongoose-findone-old-data-issue
> db.users.find({ username: 'Hannah'}).pretty()
{
    "_id" : ObjectId("59f045287a2de871d0fbce14"),
    "updatedAt" : ISODate("2017-10-25T08:02:48.153Z"),
    "createdAt" : ISODate("2017-10-25T08:02:48.107Z"),
    "username" : "Hannah",
    "active" : true,
    "__v" : 0
}
Run Code Online (Sandbox Code Playgroud)