Repository: Automattic/mongoose (JavaScript)

Issue:
'document' parameter is a function in post save middleware
### Prerequisites

- [X] I have written a descriptive issue title
- [X] I have searched existing issues to ensure the bug has not already been reported


### Mongoose version

6.9.1

### Node.js version

19.5.0

### MongoDB server version

6.0.4

### Typescript version (if applicable)

_No response_

### Description

Hi. When `bulkSave()` is called, it fires post save middleware, but for some reason, the `doc` parameter is a function, but typings indicate it should be a document. Using `this` works tho.
Apart from that, what is the proper way to get a document? Docs list these 2 ways, but I couldn't find the difference between them in the docs.

### Steps to Reproduce

```js
import mongoose from "mongoose";

mongoose.set("debug", true);
await mongoose.connect("mongodb://127.0.0.1:27017/mongooseissue");

const schema = new mongoose.Schema({ foo: Boolean, bar: Boolean });

schema.post("save", function (doc) {
    // 'doc' is typed as:
    // mongoose.Document<unknown, any, { foo?: boolean | undefined; bar?: boolean | undefined; }> & { foo?: boolean | undefined; bar?: boolean | undefined; } & { _id: mongoose.Types.ObjectId; }
    console.log("this:");
    console.log(this);
    console.log("doc:");
    console.log(doc);
})

const TestModel = mongoose.model("test", schema);

async function one() {
    const doc = new TestModel({ foo: true, bar: true });
    await doc.save();
    // 'this' and 'doc' are printed in post middleware, they're equal
}

async function two() {
    const docs = await TestModel.find({}).exec();
    docs.forEach(doc => {
        doc.foo = false;
    })
    await TestModel.bulkSave(docs);
    // 'this' is a document
    // 'doc' parameter is a function, why?
}

console.log("One");
await one();

console.log("Two");
await two();
```

### Expected Behavior

The `doc` parameter is a document


Discussion:
```javascript
const mongoose = require('mongoose');

mongoose.set("debug", true);

async function run() {
  await mongoose.connect("mongodb://127.0.0.1:27017/mongooseissue");
  await mongoose.connection.dropDatabase();

  console.log("One");
  await one();

  console.log("Two");
  await two();
}

const schema = new mongoose.Schema({ foo: Boolean, bar: Boolean });

schema.post("save", function (doc) {
    // 'doc' is typed as:
    // mongoose.Document<unknown, any, { foo?: boolean | undefined; bar?: boolean | undefined; }> & { foo?: boolean | undefined; bar?: boolean | undefined; } & { _id: mongoose.Types.ObjectId; }
    console.log("this:");
    console.log(this);
    console.log("doc:");
    console.log(doc);
})

const TestModel = mongoose.model("test", schema);

async function one() {
    const doc = new TestModel({ foo: true, bar: true });
    await doc.save();
    // 'this' and 'doc' are printed in post middleware, they're equal
}

async function two() {
    const docs = await TestModel.find({}).exec();
    docs.forEach(doc => {
        doc.foo = false;
    })
    await TestModel.bulkSave(docs);
    // 'this' is a document
    // 'doc' parameter is a function, why?
}

run();

```



Patch:
diff --git a/lib/model.js b/lib/model.js
index 0269cb1fcfd..bf0325f8f5d 100644
--- a/lib/model.js
+++ b/lib/model.js
@@ -3807,7 +3807,7 @@ function handleSuccessfulWrite(document) {
     }
 
     document.$__reset();
-    document.schema.s.hooks.execPost('save', document, {}, (err) => {
+    document.schema.s.hooks.execPost('save', document, [document], {}, (err) => {
       if (err) {
         reject(err);
         return;


Test patch:
diff --git a/test/model.test.js b/test/model.test.js
index 7d71d07783c..6b697475b21 100644
--- a/test/model.test.js
+++ b/test/model.test.js
@@ -3153,6 +3153,28 @@ describe('Model', function() {
           done();
         });
       });
+
+      it('callback should receive parameter of type document after bulkSave (gh-13026)', async function() {
+        const schema = new Schema({
+          foo: Boolean,
+          bar: Boolean
+        });
+
+        schema.post('save', function(doc) {
+          assert.deepEqual(this, doc);
+        });
+
+        const Test = db.model('Test', schema);
+
+        await Test.create({
+          foo: true,
+          bar: true
+        });
+
+        const tests = await Test.find();
+        tests.forEach(t => t.foo = false);
+        await Test.bulkSave(tests);
+      });
     });
   });