MongoDB文档插入 #

一、文档概述 #

1.1 文档概念 #

文档(Document)是MongoDB中数据的基本单位,以BSON格式存储,类似于JSON对象。

javascript
// 简单文档
{
    "_id": ObjectId("507f1f77bcf86cd799439011"),
    "name": "John",
    "age": 25,
    "email": "john@example.com"
}

// 复杂文档
{
    "_id": ObjectId("507f1f77bcf86cd799439012"),
    "name": "Jane",
    "address": {
        "city": "Beijing",
        "street": "Chaoyang Road"
    },
    "hobbies": ["reading", "swimming"],
    "createdAt": ISODate("2024-01-01T00:00:00Z")
}

1.2 文档结构 #

text
文档结构
├── _id (主键,自动生成)
├── 字段名 (键)
│   └── 字段值 (值)
├── 嵌套文档
└── 数组字段

1.3 文档限制 #

限制 说明
大小 单个文档最大16MB
嵌套深度 最多100层
字段名 不能包含$和.
_id 必须唯一

二、insertOne方法 #

2.1 基本插入 #

javascript
// 插入单个文档
db.users.insertOne({
    name: "John",
    age: 25,
    email: "john@example.com"
})

// 输出
{
    "acknowledged": true,
    "insertedId": ObjectId("65f1a2b3c4d5e6f7g8h9i0j1")
}

2.2 插入带_id的文档 #

javascript
// 指定_id
db.users.insertOne({
    _id: 1,
    name: "John",
    age: 25
})

// 输出
{
    "acknowledged": true,
    "insertedId": 1
}

2.3 插入嵌套文档 #

javascript
// 插入嵌套文档
db.users.insertOne({
    name: "John",
    address: {
        city: "Beijing",
        street: "Chaoyang Road",
        zipCode: "100000"
    },
    profile: {
        avatar: "avatar.jpg",
        bio: "Software Developer"
    }
})

2.4 插入数组字段 #

javascript
// 插入数组字段
db.users.insertOne({
    name: "John",
    hobbies: ["reading", "swimming", "coding"],
    scores: [85, 90, 78, 92],
    education: [
        { school: "MIT", degree: "Bachelor", year: 2020 },
        { school: "Stanford", degree: "Master", year: 2022 }
    ]
})

2.5 插入选项 #

javascript
// 插入选项
db.users.insertOne(
    {
        name: "John",
        age: 25
    },
    {
        writeConcern: { w: "majority", j: true },
        ordered: true
    }
)

三、insertMany方法 #

3.1 批量插入 #

javascript
// 插入多个文档
db.users.insertMany([
    { name: "John", age: 25, city: "Beijing" },
    { name: "Jane", age: 28, city: "Shanghai" },
    { name: "Bob", age: 30, city: "Guangzhou" }
])

// 输出
{
    "acknowledged": true,
    "insertedIds": [
        ObjectId("65f1a2b3c4d5e6f7g8h9i0j1"),
        ObjectId("65f1a2b3c4d5e6f7g8h9i0j2"),
        ObjectId("65f1a2b3c4d5e6f7g8h9i0j3")
    ]
}

3.2 有序插入 #

javascript
// 有序插入(遇到错误停止)
db.users.insertMany(
    [
        { _id: 1, name: "John" },
        { _id: 1, name: "Jane" },  // 重复_id
        { _id: 2, name: "Bob" }
    ],
    { ordered: true }  // 默认
)

// 第一个文档插入成功,第二个失败,第三个不会插入
// 报错:E11000 duplicate key error

3.3 无序插入 #

javascript
// 无序插入(遇到错误继续)
db.users.insertMany(
    [
        { _id: 1, name: "John" },
        { _id: 1, name: "Jane" },  // 重复_id
        { _id: 2, name: "Bob" }
    ],
    { ordered: false }
)

// 第一个文档插入成功,第二个失败,第三个继续插入
// 报错:部分文档插入失败

3.4 大批量插入 #

javascript
// 大批量插入
const documents = []
for (let i = 0; i < 10000; i++) {
    documents.push({
        name: `user_${i}`,
        age: Math.floor(Math.random() * 50) + 18,
        createdAt: new Date()
    })
}

db.users.insertMany(documents, { ordered: false })

四、insert方法(已废弃) #

4.1 基本用法 #

javascript
// insert方法(已废弃,不推荐使用)
db.users.insert({
    name: "John",
    age: 25
})

// 插入多个文档
db.users.insert([
    { name: "John", age: 25 },
    { name: "Jane", age: 28 }
])

注意: insert方法已废弃,推荐使用insertOne和insertMany。

五、批量写入 #

5.1 bulkWrite方法 #

javascript
// 批量写入操作
db.users.bulkWrite([
    {
        insertOne: {
            document: { name: "John", age: 25 }
        }
    },
    {
        insertOne: {
            document: { name: "Jane", age: 28 }
        }
    },
    {
        updateOne: {
            filter: { name: "Bob" },
            update: { $set: { age: 30 } }
        }
    },
    {
        deleteOne: {
            filter: { name: "Alice" }
        }
    }
])

// 输出
{
    "acknowledged": true,
    "insertedCount": 2,
    "insertedIds": {
        "0": ObjectId("..."),
        "1": ObjectId("...")
    },
    "matchedCount": 1,
    "modifiedCount": 1,
    "deletedCount": 1
}

5.2 批量插入优化 #

javascript
// 分批插入大量数据
const batchSize = 1000
const totalDocuments = 100000

for (let i = 0; i < totalDocuments; i += batchSize) {
    const batch = []
    for (let j = 0; j < batchSize && i + j < totalDocuments; j++) {
        batch.push({
            name: `user_${i + j}`,
            age: Math.floor(Math.random() * 50) + 18,
            createdAt: new Date()
        })
    }
    db.users.insertMany(batch, { ordered: false })
}

六、插入选项 #

6.1 writeConcern选项 #

javascript
// 写关注级别
db.users.insertOne(
    { name: "John", age: 25 },
    {
        writeConcern: {
            w: "majority",  // 写入大多数节点
            j: true,        // 写入日志
            wtimeout: 5000  // 超时时间
        }
    }
)

写关注级别:

级别 说明
w: 0 不确认写入
w: 1 确认主节点写入
w: “majority” 确认大多数节点写入
w: n 确认n个节点写入

6.2 ordered选项 #

javascript
// 有序插入
db.users.insertMany(
    [...],
    { ordered: true }  // 遇到错误停止
)

// 无序插入
db.users.insertMany(
    [...],
    { ordered: false }  // 遇到错误继续
)

七、插入验证 #

7.1 文档验证 #

javascript
// 创建带验证规则的集合
db.createCollection("users", {
    validator: {
        $jsonSchema: {
            bsonType: "object",
            required: ["name", "email"],
            properties: {
                name: { bsonType: "string" },
                email: { bsonType: "string" },
                age: { bsonType: "int", minimum: 0 }
            }
        }
    }
})

// 插入有效文档
db.users.insertOne({
    name: "John",
    email: "john@example.com",
    age: NumberInt(25)
})
// 成功

// 插入无效文档
db.users.insertOne({
    name: "John"
    // 缺少email字段
})
// 报错:Document failed validation

7.2 绕过验证 #

javascript
// 绕过文档验证
db.users.insertOne(
    { name: "John" },  // 缺少email
    { bypassDocumentValidation: true }
)

八、插入错误处理 #

8.1 重复键错误 #

javascript
// 插入重复_id
db.users.insertOne({ _id: 1, name: "John" })
db.users.insertOne({ _id: 1, name: "Jane" })
// 报错:E11000 duplicate key error

// 使用try-catch处理
try {
    db.users.insertOne({ _id: 1, name: "Jane" })
} catch (error) {
    if (error.code === 11000) {
        print("文档已存在")
    }
}

8.2 验证错误 #

javascript
// 处理验证错误
try {
    db.users.insertOne({
        name: "John",
        age: -1  // 年龄为负数
    })
} catch (error) {
    if (error.code === 121) {
        print("文档验证失败: " + error.message)
    }
}

8.3 网络错误 #

javascript
// 处理网络错误
try {
    db.users.insertOne({ name: "John" })
} catch (error) {
    if (error.name === "MongoNetworkError") {
        print("网络错误: " + error.message)
    }
}

九、插入性能 #

9.1 批量插入优化 #

javascript
// 推荐:批量插入
db.users.insertMany([...])

// 不推荐:循环单条插入
for (let i = 0; i < 1000; i++) {
    db.users.insertOne({ name: `user_${i}` })
}

9.2 无序插入优化 #

javascript
// 无序插入更快
db.users.insertMany([...], { ordered: false })

9.3 写关注优化 #

javascript
// 降低写关注级别提高性能(开发环境)
db.users.insertOne(
    { name: "John" },
    { writeConcern: { w: 1 } }
)

// 高写关注级别(生产环境)
db.users.insertOne(
    { name: "John" },
    { writeConcern: { w: "majority", j: true } }
)

十、插入最佳实践 #

10.1 文档设计 #

javascript
// 推荐:扁平化设计
{
    name: "John",
    email: "john@example.com",
    city: "Beijing",
    createdAt: new Date()
}

// 避免:过度嵌套
{
    user: {
        profile: {
            personal: {
                info: {
                    name: "John"
                }
            }
        }
    }
}

10.2 字段命名 #

javascript
// 推荐:简短明确的字段名
{
    name: "John",
    email: "john@example.com",
    createdAt: new Date()
}

// 避免:过长的字段名
{
    user_full_name: "John",
    user_email_address: "john@example.com",
    user_account_creation_timestamp: new Date()
}

10.3 批量插入 #

javascript
// 推荐:合理分批
const batchSize = 1000
for (let i = 0; i < totalDocuments; i += batchSize) {
    const batch = createBatch(i, batchSize)
    db.users.insertMany(batch, { ordered: false })
}

// 避免:一次性插入过多
db.users.insertMany(hugeArray)  // 可能超出内存限制

十一、常见问题 #

11.1 文档过大 #

javascript
// 问题:文档超过16MB
db.users.insertOne({
    data: largeData  // 超过16MB
})
// 报错:document too large

// 解决:使用GridFS
db.fs.files.insertOne({
    filename: "large_file.pdf",
    length: NumberLong(104857600)
})

11.2 插入速度慢 #

javascript
// 原因:有序插入、高写关注、索引过多

// 解决:
// 1. 使用无序插入
db.users.insertMany([...], { ordered: false })

// 2. 降低写关注
db.users.insertOne({...}, { writeConcern: { w: 1 } })

// 3. 批量插入
db.users.insertMany([...])

11.3 内存不足 #

javascript
// 问题:批量插入导致内存不足

// 解决:分批插入
const batchSize = 1000
for (let i = 0; i < totalDocuments; i += batchSize) {
    const batch = documents.slice(i, i + batchSize)
    db.users.insertMany(batch, { ordered: false })
}

十二、总结 #

插入操作速查表:

方法 说明 示例
insertOne 插入单个文档 db.coll.insertOne({…})
insertMany 插入多个文档 db.coll.insertMany([…])
bulkWrite 批量写入 db.coll.bulkWrite([…])

插入选项:

选项 说明 默认值
ordered 有序插入 true
writeConcern 写关注
bypassDocumentValidation 绕过验证 false

下一步,让我们学习文档更新!

最后更新:2026-03-27