阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 创建文档(Create)

创建文档(Create)

作者:陈川 阅读数:30167人阅读 分类: MongoDB

创建文档(Create)

Mongoose 提供了多种方法来创建文档并将其保存到 MongoDB 数据库。最常用的方法是使用模型实例的 save() 方法,或者直接使用模型的 create() 方法。这两种方法各有优缺点,适用于不同的场景。

使用 save() 方法创建文档

save() 方法是 Mongoose 文档实例的一个方法,用于将文档保存到数据库。首先需要创建一个模型实例,然后调用 save() 方法。

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

// 定义模式
const userSchema = new Schema({
  name: String,
  age: Number,
  email: String
});

// 创建模型
const User = mongoose.model('User', userSchema);

// 创建文档实例
const newUser = new User({
  name: '张三',
  age: 25,
  email: 'zhangsan@example.com'
});

// 保存文档
newUser.save()
  .then(doc => {
    console.log('文档保存成功:', doc);
  })
  .catch(err => {
    console.error('保存失败:', err);
  });

save() 方法返回一个 Promise,可以使用 then()catch() 处理成功和失败的情况。这种方法的好处是可以对文档进行修改后再保存,灵活性较高。

使用 create() 方法创建文档

create() 是模型上的一个静态方法,可以直接创建并保存文档。它实际上是 new Model()save() 的快捷方式。

User.create({
  name: '李四',
  age: 30,
  email: 'lisi@example.com'
})
  .then(doc => {
    console.log('文档创建成功:', doc);
  })
  .catch(err => {
    console.error('创建失败:', err);
  });

create() 方法也可以接受一个数组,用于批量创建文档:

User.create([
  { name: '王五', age: 28, email: 'wangwu@example.com' },
  { name: '赵六', age: 35, email: 'zhaoliu@example.com' }
])
  .then(docs => {
    console.log('批量创建成功:', docs);
  })
  .catch(err => {
    console.error('批量创建失败:', err);
  });

插入多个文档

除了使用 create() 方法批量插入外,还可以使用 insertMany() 方法。这种方法比循环调用 save()create() 更高效。

User.insertMany([
  { name: '钱七', age: 22, email: 'qianqi@example.com' },
  { name: '孙八', age: 40, email: 'sunba@example.com' }
])
  .then(docs => {
    console.log('批量插入成功:', docs);
  })
  .catch(err => {
    console.error('批量插入失败:', err);
  });

验证和钩子

在创建文档时,Mongoose 会自动执行模式中定义的验证。如果验证失败,文档将不会被保存。

const invalidUser = new User({
  name: '周九',
  age: '不是数字',  // 这将触发验证错误
  email: 'zhoujiu@example.com'
});

invalidUser.save()
  .then(doc => {
    console.log('文档保存成功:', doc);
  })
  .catch(err => {
    console.error('验证失败:', err.message);
    // 输出: "验证失败: User validation failed: age: Cast to Number failed for value \"不是数字\" (type string) at path \"age\""
  });

还可以使用 pre-save 钩子在保存前对文档进行处理:

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

原子性和事务

在 MongoDB 4.0+ 中,可以使用事务来确保多个操作的原子性。Mongoose 也支持这一特性:

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

try {
  const user1 = await User.create([{ name: '用户1' }], { session });
  const user2 = await User.create([{ name: '用户2' }], { session });
  
  await session.commitTransaction();
  console.log('事务提交成功');
} catch (error) {
  await session.abortTransaction();
  console.error('事务回滚:', error);
} finally {
  session.endSession();
}

性能考虑

当需要插入大量文档时,使用 insertMany() 比循环调用 save()create() 更高效。insertMany() 会批量发送操作到数据库,减少网络往返次数。

// 低效的方式
for (let i = 0; i < 1000; i++) {
  await User.create({ name: `用户${i}` });
}

// 高效的方式
const users = [];
for (let i = 0; i < 1000; i++) {
  users.push({ name: `用户${i}` });
}
await User.insertMany(users);

错误处理

在创建文档时,应该妥善处理可能出现的错误。常见的错误包括验证错误、唯一键冲突等。

try {
  const user = await User.create({
    email: 'existing@example.com'  // 假设这个邮箱已经存在且设置了唯一索引
  });
} catch (err) {
  if (err.code === 11000) {
    console.error('邮箱已存在');
  } else {
    console.error('其他错误:', err);
  }
}

默认值和自动填充

可以在模式中定义默认值,Mongoose 会在创建文档时自动填充:

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: '商品1', price: 100 });
console.log(newProduct.inStock);  // 输出: true
console.log(newProduct.createdAt);  // 输出: 当前时间

自定义 _id

默认情况下,Mongoose 会为每个文档自动生成一个 _id。如果需要自定义 _id,可以直接在创建时指定:

const customIdUser = await User.create({
  _id: 'custom123',
  name: '自定义ID用户'
});
console.log(customIdUser._id);  // 输出: "custom123"

使用原始驱动方法

在某些情况下,可能需要绕过 Mongoose 的特性直接使用 MongoDB 原生驱动的方法:

const result = await User.collection.insertOne({
  name: '原生驱动用户',
  age: 45
});
console.log(result.insertedId);

这种方法不会触发 Mongoose 的中间件和验证,但性能更高。

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

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

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌