The `create()` Function in Mongoose
Mongoose models have a create()
function that is often used to create new documents.
const User = mongoose.model('User', mongoose.Schema({
email: String
}));
const doc = await User.create({ email: 'bill@microsoft.com' });
doc instanceof User; // true
doc.email; // 'bill@microsoft.com'
The create()
function is a thin wrapper around the save()
function.
The above create()
call is equivalent to:
const doc = new User({ email: 'bill@microsoft.com' });
await doc.save();
The most common reason for using create()
is that you can conveniently save()
multiple
documents with a single function call by passing an array of objects:
const User = mongoose.model('User', mongoose.Schema({
email: String
}));
const docs = await User.create([
{ email: 'sergey@google.com' },
{ email: 'bill@microsoft.com' }
]);
docs[0] instanceof User; // true
docs[0].email; // 'sergey@google.com'
docs[1].email; // 'bill@microsoft.com'
With Sessions and Transactions
In addition to passing an array of objects, create()
also supports passing in a single
object, or a spread of objects. For example, below is another way you can create multiple documents.
// Saves two new documents.
await User.create({ email: 'sergey@google.com' }, { email: 'bill@microsoft.com' });
The spread syntax unfortunately leads to syntactic ambiguity if you want to pass options to
the create()
function, like if you want to use transactions. For example, the below code will attempt to create two documents, rather
than treating the 2nd parameter as an options
object.
const session = await User.startSession();
await session.withTransaction(async () => {
// Be careful, the below does **not** work! Instead of creating one document with the
// associated session, it creates two documents with no session!
await User.create({ email: 'sergey@google.com' }, { session });
});
Because of this, if you want to use create()
in a transaction, you must pass the
documents as an array, even if you're only creating one document.
const session = await User.startSession();
await session.withTransaction(async () => {
// Creates one document with the given session. Note the `[]`!
await User.create([{ email: 'sergey@google.com' }], { session });
});
Versus insertMany()
Models also have an insertMany()
function that is syntactically similar to create()
.
const User = mongoose.model('User', mongoose.Schema({
email: String
}));
const [doc] = await User.insertMany([{ email: 'bill@microsoft.com' }]);
doc instanceof User; // true
doc.email; // 'bill@microsoft.com'
The biggest difference is that insertMany()
ends up as one atomic insertMany()
command
that Mongoose sends to the MongoDB server, but create()
ends up as a bunch
of separate insertOne()
calls. While this means insertMany()
is usually faster,
it also means insertMany()
is more susceptible to slow trains. Because of this, we recommend using create()
instead of
insertMany()
, unless you're willing to risk slowing down other operations to make your bulk insert fast.
Another difference is that create()
triggers save()
middleware, because create()
calls save()
internally. insertMany()
does not trigger save()
middleware, but it does trigger insertMany()
middleware.