@@ -151,6 +151,62 @@ Model.prototype.$isMongooseModelPrototype = true;
151151
152152Model . prototype . db ;
153153
154+ /**
155+ * Changes the Connection instance this model uses to make requests to MongoDB.
156+ * This function is most useful for changing the Connection that a Model defined using `mongoose.model()` uses
157+ * after initialization.
158+ *
159+ * #### Example:
160+ *
161+ * await mongoose.connect('mongodb://127.0.0.1:27017/db1');
162+ * const UserModel = mongoose.model('User', mongoose.Schema({ name: String }));
163+ * UserModel.connection === mongoose.connection; // true
164+ *
165+ * const conn2 = await mongoose.createConnection('mongodb://127.0.0.1:27017/db2').asPromise();
166+ * UserModel.useConnection(conn2); // `UserModel` now stores documents in `db2`, not `db1`
167+ *
168+ * UserModel.connection === mongoose.connection; // false
169+ * UserModel.connection === conn2; // true
170+ *
171+ * conn2.model('User') === UserModel; // true
172+ * mongoose.model('User'); // Throws 'MissingSchemaError'
173+ *
174+ * Note: `useConnection()` does **not** apply any [connection-level plugins](https://mongoosejs.com/docs/api/connection.html#Connection.prototype.plugin()) from the new connection.
175+ * If you use `useConnection()` to switch a model's connection, the model will still have the old connection's plugins.
176+ *
177+ * @function useConnection
178+ * @param [Connection] connection The new connection to use
179+ * @return [Model] this
180+ * @api public
181+ */
182+
183+ Model . useConnection = function useConnection ( connection ) {
184+ if ( ! connection ) {
185+ throw new Error ( 'Please provide a connection.' ) ;
186+ }
187+ if ( this . db ) {
188+ delete this . db . models [ this . modelName ] ;
189+ delete this . prototype . db ;
190+ delete this . prototype [ modelDbSymbol ] ;
191+ delete this . prototype . collection ;
192+ delete this . prototype . $collection ;
193+ delete this . prototype [ modelCollectionSymbol ] ;
194+ }
195+
196+ this . db = connection ;
197+ const collection = connection . collection ( this . modelName , connection . options ) ;
198+ this . prototype . collection = collection ;
199+ this . prototype . $collection = collection ;
200+ this . prototype [ modelCollectionSymbol ] = collection ;
201+ this . prototype . db = connection ;
202+ this . prototype [ modelDbSymbol ] = connection ;
203+ this . collection = collection ;
204+ this . $__collection = collection ;
205+ connection . models [ this . modelName ] = this ;
206+
207+ return this ;
208+ } ;
209+
154210/**
155211 * The collection instance this model uses.
156212 * A Mongoose collection is a thin wrapper around a [MongoDB Node.js driver collection]([MongoDB Node.js driver collection](https://mongodb.github.io/node-mongodb-native/Next/classes/Collection.html)).
@@ -1246,19 +1302,21 @@ Model.syncIndexes = async function syncIndexes(options) {
12461302 throw new MongooseError ( 'Model.syncIndexes() no longer accepts a callback' ) ;
12471303 }
12481304
1249- const model = this ;
1305+ const autoCreate = options ?. autoCreate ?? this . schema . options ?. autoCreate ?? this . db . config . autoCreate ?? true ;
12501306
1251- try {
1252- await model . createCollection ( ) ;
1253- } catch ( err ) {
1254- if ( err != null && ( err . name !== 'MongoServerError' || err . code !== 48 ) ) {
1255- throw err ;
1307+ if ( autoCreate ) {
1308+ try {
1309+ await this . createCollection ( ) ;
1310+ } catch ( err ) {
1311+ if ( err != null && ( err . name !== 'MongoServerError' || err . code !== 48 ) ) {
1312+ throw err ;
1313+ }
12561314 }
12571315 }
12581316
1259- const diffIndexesResult = await model . diffIndexes ( { indexOptionsToCreate : true } ) ;
1260- const dropped = await model . cleanIndexes ( { ...options , toDrop : diffIndexesResult . toDrop } ) ;
1261- await model . createIndexes ( { ...options , toCreate : diffIndexesResult . toCreate } ) ;
1317+ const diffIndexesResult = await this . diffIndexes ( { indexOptionsToCreate : true } ) ;
1318+ const dropped = await this . cleanIndexes ( { ...options , toDrop : diffIndexesResult . toDrop } ) ;
1319+ await this . createIndexes ( { ...options , toCreate : diffIndexesResult . toCreate } ) ;
12621320
12631321 return dropped ;
12641322} ;
@@ -1471,7 +1529,7 @@ function getIndexesToDrop(schema, schemaIndexes, dbIndexes) {
14711529 * @param {Object } [options]
14721530 * @param {Array<String> } [options.toDrop] if specified, contains a list of index names to drop
14731531 * @param {Boolean } [options.hideIndexes=false] set to `true` to hide indexes instead of dropping. Requires MongoDB server 4.4 or higher
1474- * @return {Promise<String> } list of dropped or hidden index names
1532+ * @return {Promise<Array< String> > } list of dropped or hidden index names
14751533 * @api public
14761534 */
14771535
@@ -2115,9 +2173,8 @@ Model.estimatedDocumentCount = function estimatedDocumentCount(options) {
21152173 *
21162174 * #### Example:
21172175 *
2118- * Adventure.countDocuments({ type: 'jungle' }, function (err, count) {
2119- * console.log('there are %d jungle adventures', count);
2120- * });
2176+ * const count = await Adventure.countDocuments({ type: 'jungle' });
2177+ * console.log('there are %d jungle adventures', count);
21212178 *
21222179 * If you want to count all documents in a large collection,
21232180 * use the [`estimatedDocumentCount()` function](https://mongoosejs.com/docs/api/model.html#Model.estimatedDocumentCount())
@@ -2627,6 +2684,10 @@ Model.create = async function create(doc, options) {
26272684
26282685 delete options . aggregateErrors ; // dont pass on the option to "$save"
26292686
2687+ if ( options . session && ! options . ordered && args . length > 1 ) {
2688+ throw new MongooseError ( 'Cannot call `create()` with a session and multiple documents unless `ordered: true` is set' ) ;
2689+ }
2690+
26302691 if ( options . ordered ) {
26312692 for ( let i = 0 ; i < args . length ; i ++ ) {
26322693 try {
@@ -2713,6 +2774,49 @@ Model.create = async function create(doc, options) {
27132774 return res ;
27142775} ;
27152776
2777+ /**
2778+ * Shortcut for saving one document to the database.
2779+ * `MyModel.insertOne(obj, options)` is almost equivalent to `new MyModel(obj).save(options)`.
2780+ * The difference is that `insertOne()` checks if `obj` is already a document, and checks for discriminators.
2781+ *
2782+ * This function triggers the following middleware.
2783+ *
2784+ * - `save()`
2785+ *
2786+ * #### Example:
2787+ *
2788+ * // Insert one new `Character` document
2789+ * const character = await Character.insertOne({ name: 'Jean-Luc Picard' });
2790+ * character.name; // 'Jean-Luc Picard'
2791+ *
2792+ * // Create a new character within a transaction.
2793+ * await Character.insertOne({ name: 'Jean-Luc Picard' }, { session });
2794+ *
2795+ * @param {Object|Document } doc Document to insert, as a POJO or Mongoose document
2796+ * @param {Object } [options] Options passed down to `save()`.
2797+ * @return {Promise<Document> } resolves to the saved document
2798+ * @api public
2799+ */
2800+
2801+ Model . insertOne = async function insertOne ( doc , options ) {
2802+ _checkContext ( this , 'insertOne' ) ;
2803+
2804+ const discriminatorKey = this . schema . options . discriminatorKey ;
2805+ const Model = this . discriminators && doc [ discriminatorKey ] != null ?
2806+ this . discriminators [ doc [ discriminatorKey ] ] || getDiscriminatorByValue ( this . discriminators , doc [ discriminatorKey ] ) :
2807+ this ;
2808+ if ( Model == null ) {
2809+ throw new MongooseError (
2810+ `Discriminator "${ doc [ discriminatorKey ] } " not found for model "${ this . modelName } "`
2811+ ) ;
2812+ }
2813+ if ( ! ( doc instanceof Model ) ) {
2814+ doc = new Model ( doc ) ;
2815+ }
2816+
2817+ return await doc . $save ( options ) ;
2818+ } ;
2819+
27162820/**
27172821 * _Requires a replica set running MongoDB >= 3.6.0._ Watches the
27182822 * underlying collection for changes using
0 commit comments