MongoDB 大数据备份,新手教程

在 MongoDB 中,将数据复制到备份集合(归档集合)方案有很多种,操作流程与示例演示

1、方案介绍

方案一:$merge (最推荐,原子操作)

$merge 是 MongoDB 4.2+ 引入的特性,可以将聚合管道的结果写入指定的集合。当目标集合和源集合在同一个数据库时,这是性能最高的方式,因为它完全在数据库引擎内部完成。

目标 :将 sales 集合中 2024 年的所有文档复制到 sales_archive_2024 集合。

javascript 复制代码
use your_database;

// 1. 执行复制操作
db.sales.aggregate([
    { 
        $match: { 
            create_time: { 
                $gte: ISODate("2024-01-01T00:00:00Z"), 
                $lt: ISODate("2025-01-01T00:00:00Z") 
            } 
        } 
    },
    { 
        $merge: { 
            into: "sales_archive_2024",   // 目标集合名
            on: "_id",                    // 基于_id去重(防止重复插入)
            whenMatched: "replace",       // 如果_id已存在则覆盖
            whenNotMatched: "insert"      // 如果不存在则插入
        } 
    }
]);

参数详解

  • on: "_id":指定用 _id 字段来判断文档是否已存在,这是防止意外重复执行导致数据翻倍的关键。

  • whenMatched: "replace":如果目标集合中已存在相同 _id 的文档,就用新文档覆盖它。这保证了操作的幂等性,你可以安全地多次执行。

  • whenNotMatched: "insert":如果不存在,则正常插入。

验证:执行后,你可以通过以下命令快速确认复制的数据量是否一致。

javascript 复制代码
// 统计源集合中2024年的文档数
db.sales.countDocuments({ 
    create_time: { $gte: ISODate("2024-01-01T00:00:00Z"), $lt: ISODate("2025-01-01T00:00:00Z") } 
});

// 统计归档集合中的文档数
db.sales_archive_2024.countDocuments();

方案二:find() + insertMany() (适合较旧版本或小批量数据)

方案三:bulkWrite 分批处理(处理大数据集的安全方式)

如果数据量巨大(千万级以上),且因某些原因不能使用 $merge,用 bulkWrite 结合 skip/limit 进行分批复制是最安全的。

javascript 复制代码
const batchSize = 5000;
let processed = 0;
let hasMore = true;

while (hasMore) {
    // 每次从源表取5000条
    const batch = db.sales.find({ 
        create_time: { $gte: ISODate("2024-01-01T00:00:00Z"), $lt: ISODate("2025-01-01T00:00:00Z") } 
    }).skip(processed).limit(batchSize).toArray();

    if (batch.length === 0) {
        hasMore = false;
        break;
    }

    // 构建批量插入操作
    const operations = batch.map(doc => ({
        insertOne: { document: doc }
    }));

    db.sales_archive_2024.bulkWrite(operations, { ordered: false });
    
    processed += batch.length;
    print(`已复制 ${processed} 条文档...`);
}

2、复制后的清理与空间回收

完成复制并验证数据完整性后,就可以安全地删除源数据了。

2.1 删除源数据(分批进行):

javascript 复制代码
// 同样,建议分批删除,避免大事务
const sixMonthsAgo = new Date();
sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6);

while (db.sales.find({ create_time: { $lt: sixMonthsAgo } }).count() > 0) {
    db.sales.deleteMany({ create_time: { $lt: sixMonthsAgo } }, { limit: 5000 });
    sleep(100); // 每批暂停100ms
}

2.2 回收磁盘空间(维护窗口执行):

删除操作后,MongoDB 的磁盘空间不会自动释放。你需要执行压缩:

javascript 复制代码
// 在主节点执行会阻塞读写,建议在从节点执行或安排维护时间
db.runCommand({ compact: "sales" });

3、演示示例

3.1 MongoDB控制台操作

bash 复制代码
1、连接操作台:
mongosh "mongodb://localhost:27017"

2、显示数据库:
show databases

3、切换到指定数据库(如果不存在则创建):

use <database_name>

4、查看当前所使用的数据库:
db

5、显示当前数据库中的所有集合:
show collections

3.2 复制集合操作如下命令

javascript 复制代码
db.t_order_package.aggregate([
    { 
        $match: { 
            date: { $gte: "2025-01-01", $lte: "2025-12-31" } //日期大于等于"2025-01-01",小于等于"2025-12-31" 
        } 
    },
    { 
        $merge: { 
            into: "t_order_package_2025",// 目标集合名
            on: "_id",// 基于_id去重(防止重复插入)
            whenMatched: "replace",// 如果_id已存在则覆盖
            whenNotMatched: "insert"// 如果不存在则插入
        } 
    }
]);

这样操作后,会将集合"t_order_package"按照条件复制内容到"t_order_package_2025"集合里

注:几百万的数据量也是可以直接复制的

3.3 验证数据集

javascript 复制代码
//按指南条件查询原数据集的数据量
db.t_order_package.countDocuments({ 
    date: { $gte: "2025-01-01", $lte: "2025-12-31" } 
});

// 统计归档集合数据量
db.t_order_package_2025.countDocuments();

//若他们数据量相等,说明复制正确

3.4 删除原数据集的数据

javascript 复制代码
//尽量分批操作
db.t_order_package.deleteMany({date:{$lte:"2024-12-31"}});

//指定条件查询原数据集的数据量
db.runCommand({compact:"t_order_package"});

3.5 回收磁盘空间

javascript 复制代码
db.runCommand({compact:"t_order_package"});
//这类似mysql的OPTIMIZE操作

4、MongoDB常用的比较操作符

常用操作符

操作符 含义 类比 SQL
$gt 于 (Greater Than) >
$gte 大于等于 (Greater Than or Equal) >=
$lt 于 (Less Than) <
$lte 小于等于 (Less Than or Equal) <=
$eq 等于 (Equal) =
$ne 不等于 (Not Equal) !=
$in 在...之中 (In) IN
$nin 不在...之中 (Not In) NOT IN

示例

javascript 复制代码
// 1. 查询 2024-01-01 之后的数据(不含当天)
db.orders.find({ date: { $gt: "2024-01-01" } });

// 2. 查询 2024-01-01 及之后的数据(含当天)
db.orders.find({ date: { $gte: "2024-01-01" } });

// 3. 查询 2024-12-31 之前的数据(不含当天)
db.orders.find({ date: { $lt: "2024-12-31" } });

// 4. 查询 2024-01-01 到 2024-12-31 之间(含首尾)
db.orders.find({ 
    date: { $gte: "2024-01-01", $lte: "2024-12-31" } 
});

// 5. 查询 status 不等于 0 的数据
db.orders.find({ status: { $ne: 0 } });

// 6. 查询 status 为 0 或 1 的数据
db.orders.find({ status: { $in: [0, 1] } });

字符串日期比较的注意事项

因为你的 date 字段是字符串类型(如 "2025-04-05"),字符串比较是按字典序(逐字符比较)进行的。

javascript 复制代码
// ✅ 正确:因为 "2024-01-01" < "2024-12-31" (逐位比较)
"2024-01-01" < "2024-12-31"  // true

// ✅ 正确:月份和日期是两位数,比较没问题
"2024-01-01" < "2024-01-02"  // true

// ❌ 错误:如果月份不是两位数,比较会出错
"2024-1-1" < "2024-01-01"   // false(因为 '1' > '0')

所以你的数据格式 "2025-04-05"$gte/$lte 是完全安全的。

快速记忆

G reater T han = GT → 大于

L ess T han = LT → 小于

加上 E = Equal → 加上等于

所以:

  • $gte = 大于等于

  • $lte = 小于等于

5、总结

维护时,尽量在服务器空闲时操作,操作时要细心,注意做好备份。备份数据还可以使用**mongoexport / mongoimport** 工具链

相关推荐
城数派2 小时前
1950-2026年中国0.1°逐月平均气温栅格数据集
数据库·信息可视化
livemetee2 小时前
【关于redis高性能,高可用处理】
数据库·redis·缓存
-To be number.wan2 小时前
数据库系统 | 数据库安全与完整性
数据库·学习
Omics Pro4 小时前
首个针对生物医药LLM智能体的全流程过程级评测框架
数据库·人工智能·windows·redis·量子计算
要开心吖ZSH4 小时前
MVCC 进阶:快照读 vs 当前读、幻读与 Next-Key Lock
java·数据库·sql·mysql·mvcc
水木流年追梦4 小时前
agent面试必备31- AI Agent 核心进阶:工具路由(Tool Routing)
数据库·人工智能·oracle·面试·职场和发展·embedding
xcLeigh4 小时前
KES运维自动化与脚本体系实战
运维·数据库·自动化·脚本·数据迁移·kes
大气的小蜜蜂5 小时前
领域层的服务
java·前端·数据库
翔云1234565 小时前
简单概括主库上 Executed_Gtid_Set 是什么时候更新的
数据库·mysql