Support pre('bulkWrite') middleware hook on schemas
new featureenhancementcan't reproduceStale
### Prerequisites
- [x] I have written a descriptive issue title
- [x] I have searched existing issues to ensure the feature has not already been requested
### 🚀 Feature Proposal
Mongoose supports pre() middleware hooks for most query operations (find, updateOne,
deleteMany, etc.), aggregate, save, and insertMany , but not for bulkWrite. Since
Model.bulkWrite() bypasses all schema-level middleware, there's no way to intercept or
modify bulk operations at the schema layer.
This means any cross-cutting concern implemented via schema hooks (tenant isolation,
soft-delete filters, audit logging, etc.) silently breaks when bulkWrite is used.
Developers must implement application-layer workarounds to replicate what hooks do for
every other operation.
### Motivation
We're building multi-tenant isolation using schema pre() hooks to auto-inject a tenant
filter (id.clientId) on all queries. This works for all 13 query types, aggregate, save,
and insertMany ,but not bulkWrite. We had to implement tenant injection at the
application layer specifically for bulkWrite, creating an inconsistency where every
other Mongoose operation is protected at the schema level but bulkWrite requires a
separate code path.
This affects anyone using schema middleware for:
- Multi-tenant isolation (filter injection)
- Soft-delete patterns (auto-add { deleted: false })
- Audit logging (track who modified what)
- Field-level access control
### Example
```js
const schema = new Schema({
id: {
clientId: { type: Schema.Types.ObjectId, required: true },
},
name: String,
});
// This works for find, updateOne, deleteMany, etc.
schema.pre('find', function () {
this.where({ 'id.clientId': getCurrentTenantId() });
});
// This does NOT exist today — bulkWrite bypasses all middleware
schema.pre('bulkWrite', function (next, ops) {
ops.forEach(op => {
if (op.updateOne) {
op.updateOne.filter['id.clientId'] = getCurrentTenantId();
}
if (op.insertOne) {
op.insertOne.document['id.clientId'] = getCurrentTenantId();
}
// ... same for deleteOne, updateMany, etc.
});
next();
});
```
The pre('bulkWrite') hook would receive the operations array and allow modification
before execution, consistent with how pre('insertMany') receives the docs array.
3 条评论