The `create()` Function in Mongoose

Jul 15, 2020

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.


Want to become your team's MongoDB expert? "Mastering Mongoose" distills 8 years of hard-earned lessons building Mongoose apps at scale into 153 pages. That means you can learn what you need to know to build production-ready full-stack apps with Node.js and MongoDB in a few days. Get your copy!

More Mongoose Tutorials