You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

bcryptjs在Mongoose的insertMany方法不生效,create方法运行正常如何解决?

问题描述

环境版本

  • bcryptjs 版本:"bcryptjs": "^2.4.3"
  • mongoose 版本:"mongoose": "^6.0.12"

我需要在用户创建或密码更新时加密用户密码,使用 User.create() 创建单个用户时一切运行正常,密码成功加密;但使用 User.insertMany() 时数据虽然插入成功,密码却没有被加密。

我的 Schema 定义如下:

const userSchema = mongoose.Schema(
  {
    name: {
      type: String,
      required: true
    },
    surname: {
      type: String,
      required: true
    },
    voterId: {
      type: String,
      required: true,
      unique: true
    },
    password: {
      type: String,
      required: true,
      unique: true,
    },
    votedFor: [
      {
        type: mongoose.Schema.ObjectId,
        ref: 'Election'
      }
    ],
    finishedVoting: {
      type: Boolean,
      required: true,
      default: false
    },
    isAdmin: {
      type: Boolean,
      required: true,
      default: false,
    },
  },
  {
    timestamps: true,
  }
)

userSchema.pre('save', async function(next) {
  // 仅当密码被修改时执行该逻辑
  if (!this.isModified('password')) return next();

  // 用10轮盐值加密密码
  this.password = await bcrypt.hash(this.password, 10);

  next();
});

我尝试插入的示例数据:

const voters = [
  {
    name: "Sherali",
    surname: "Samandarov",
    voterId: "194199",
    password: "FA654644", // 预期会被加密
    isAdmin: false,
    finishedVoting: false
  },
  {
    name: "Sherali",
    surname: "Samandarov",
    voterId: "184183",
    password: "MB454644", // 预期会被加密
    isAdmin: false,
    finishedVoting: false
  },
  {
    name: "Sherali",
    surname: "Samandarov",
    voterId: "194324",
    password: "FA651684", // 预期会被加密
    isAdmin: false,
    finishedVoting: false
  }
]

我猜测是 userSchema.pre('save', ...) 钩子在调用 insertMany() 时没有被触发。


解答

问题原因

你的猜测是正确的,Mongoose 默认配置下 insertMany 方法不会触发单个文档的 save 前置钩子,该方法是直接向 MongoDB 发送批量插入请求,不会逐一对每个文档执行保存前的钩子逻辑,因此你定义的密码加密逻辑没有运行。

解决方案

以下两种方案均可解决该问题,可根据实际场景选择:

方案一:新增 insertMany 前置钩子(推荐)

在现有 Schema 中新增批量插入的前置钩子,统一处理所有批量插入场景的密码加密:

userSchema.pre('insertMany', async function(next, docs) {
  // 遍历所有待插入的文档,逐个加密密码
  for (const user of docs) {
    user.password = await bcrypt.hash(user.password, 10);
  }
  next();
});

新增该钩子后,所有调用 User.insertMany() 的场景都会自动加密密码,无需修改原有调用逻辑。

方案二:插入前手动批量加密密码

如果不想修改 Schema 定义,也可以在调用插入方法前提前处理好密码加密:

// 批量加密所有用户密码
const processedVoters = await Promise.all(
  voters.map(async (voter) => {
    voter.password = await bcrypt.hash(voter.password, 10);
    return voter;
  })
);
// 执行批量插入
await User.insertMany(processedVoters);

内容的提问来源于stack exchange,提问作者ABDULLOKH MUKHAMMADJONOV

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 21:36:03