阿里云主机折上折
  • 微信号
Current Site:Index > Create a document (Create)

Create a document (Create)

Author:Chuan Chen 阅读数:30166人阅读 分类: MongoDB

Creating Documents (Create)

Mongoose provides multiple methods to create documents and save them to a MongoDB database. The most commonly used methods are the save() method of a model instance or directly using the create() method of the model. These two methods each have their own advantages and disadvantages and are suitable for different scenarios.

Creating Documents Using the save() Method

The save() method is an instance method of a Mongoose document, used to save the document to the database. First, you need to create a model instance and then call the save() method.

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// Define the schema
const userSchema = new Schema({
  name: String,
  age: Number,
  email: String
});

// Create the model
const User = mongoose.model('User', userSchema);

// Create a document instance
const newUser = new User({
  name: 'Zhang San',
  age: 25,
  email: 'zhangsan@example.com'
});

// Save the document
newUser.save()
  .then(doc => {
    console.log('Document saved successfully:', doc);
  })
  .catch(err => {
    console.error('Save failed:', err);
  });

The save() method returns a Promise, allowing you to handle success and failure cases using then() and catch(). The advantage of this method is that it allows modifications to the document before saving, offering greater flexibility.

Creating Documents Using the create() Method

The create() method is a static method on the model that directly creates and saves a document. It is essentially a shortcut for new Model() and save().

User.create({
  name: 'Li Si',
  age: 30,
  email: 'lisi@example.com'
})
  .then(doc => {
    console.log('Document created successfully:', doc);
  })
  .catch(err => {
    console.error('Creation failed:', err);
  });

The create() method can also accept an array for batch creation of documents:

User.create([
  { name: 'Wang Wu', age: 28, email: 'wangwu@example.com' },
  { name: 'Zhao Liu', age: 35, email: 'zhaoliu@example.com' }
])
  .then(docs => {
    console.log('Batch creation successful:', docs);
  })
  .catch(err => {
    console.error('Batch creation failed:', err);
  });

Inserting Multiple Documents

In addition to using the create() method for batch insertion, you can also use the insertMany() method. This method is more efficient than looping through save() or create() calls.

User.insertMany([
  { name: 'Qian Qi', age: 22, email: 'qianqi@example.com' },
  { name: 'Sun Ba', age: 40, email: 'sunba@example.com' }
])
  .then(docs => {
    console.log('Batch insertion successful:', docs);
  })
  .catch(err => {
    console.error('Batch insertion failed:', err);
  });

Validation and Hooks

When creating documents, Mongoose automatically performs validation as defined in the schema. If validation fails, the document will not be saved.

const invalidUser = new User({
  name: 'Zhou Jiu',
  age: 'Not a number',  // This will trigger a validation error
  email: 'zhoujiu@example.com'
});

invalidUser.save()
  .then(doc => {
    console.log('Document saved successfully:', doc);
  })
  .catch(err => {
    console.error('Validation failed:', err.message);
    // Output: "Validation failed: User validation failed: age: Cast to Number failed for value \"Not a number\" (type string) at path \"age\""
  });

You can also use pre-save hooks to process documents before saving:

userSchema.pre('save', function(next) {
  if (this.isNew) {
    this.createdAt = new Date();
  }
  this.updatedAt = new Date();
  next();
});

Atomicity and Transactions

In MongoDB 4.0+, you can use transactions to ensure atomicity across multiple operations. Mongoose also supports this feature:

const session = await mongoose.startSession();
session.startTransaction();

try {
  const user1 = await User.create([{ name: 'User 1' }], { session });
  const user2 = await User.create([{ name: 'User 2' }], { session });
  
  await session.commitTransaction();
  console.log('Transaction committed successfully');
} catch (error) {
  await session.abortTransaction();
  console.error('Transaction rolled back:', error);
} finally {
  session.endSession();
}

Performance Considerations

When inserting a large number of documents, using insertMany() is more efficient than looping through save() or create() calls. insertMany() sends operations to the database in batches, reducing network round trips.

// Inefficient approach
for (let i = 0; i < 1000; i++) {
  await User.create({ name: `User ${i}` });
}

// Efficient approach
const users = [];
for (let i = 0; i < 1000; i++) {
  users.push({ name: `User ${i}` });
}
await User.insertMany(users);

Error Handling

When creating documents, you should properly handle potential errors. Common errors include validation errors and unique key conflicts.

try {
  const user = await User.create({
    email: 'existing@example.com'  // Assume this email already exists and has a unique index
  });
} catch (err) {
  if (err.code === 11000) {
    console.error('Email already exists');
  } else {
    console.error('Other error:', err);
  }
}

Default Values and Auto-Population

You can define default values in the schema, which Mongoose will automatically populate when creating documents:

const productSchema = new Schema({
  name: String,
  price: Number,
  inStock: { type: Boolean, default: true },
  createdAt: { type: Date, default: Date.now }
});

const Product = mongoose.model('Product', productSchema);

const newProduct = await Product.create({ name: 'Product 1', price: 100 });
console.log(newProduct.inStock);  // Output: true
console.log(newProduct.createdAt);  // Output: Current time

Custom _id

By default, Mongoose automatically generates an _id for each document. If you need a custom _id, you can specify it during creation:

const customIdUser = await User.create({
  _id: 'custom123',
  name: 'Custom ID User'
});
console.log(customIdUser._id);  // Output: "custom123"

Using Native Driver Methods

In some cases, you may need to bypass Mongoose features and directly use MongoDB native driver methods:

const result = await User.collection.insertOne({
  name: 'Native Driver User',
  age: 45
});
console.log(result.insertedId);

This method does not trigger Mongoose middleware or validation but offers higher performance.

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.