在 MongoDB 中,我们可能想把某个特定表的数据从一个库迁移到另外一个库。下面提供几种常见操作方法,适合数据量不大的场景。
方法一:使用 mongodump 和 mongorestore
1. 导出整个数据库
# 导出源数据库
mongodump --host localhost:27017 --db source_database --out /path/to/backup
# 导入到目标数据库
mongorestore --host localhost:27017 --db target_database /path/to/backup/source_database
2. 导出单个集合
# 导出单个集合
mongodump --host localhost:27017 --db source_database --collection collection_name --out /path/to/backup
# 导入到目标数据库
mongorestore --host localhost:27017 --db target_database --collection collection_name /path/to/backup/source_database/collection_name.bson
方法二:使用 MongoDB Shell 脚本
1. 迁移单个集合
// 连接到 MongoDB
use source_database
// 获取集合中的所有文档
var cursor = db.collection_name.find();
// 切换到目标数据库
use target_database
// 批量插入数据
var batch = [];
var batchSize = 1000;
cursor.forEach(function(doc) {
batch.push(doc);
if (batch.length === batchSize) {
db.collection_name.insertMany(batch);
batch = [];
}
});
// 插入剩余的文档
if (batch.length > 0) {
db.collection_name.insertMany(batch);
}
2. 迁移整个数据库的所有集合
// 获取源数据库的所有集合名称
use source_database
var collections = db.getCollectionNames();
collections.forEach(function(collectionName) {
// 跳过系统集合
if (collectionName.startsWith('system.')) {
return;
}
print("正在迁移集合: " + collectionName);
var cursor = db.getCollection(collectionName).find();
var batch = [];
var batchSize = 1000;
cursor.forEach(function(doc) {
batch.push(doc);
if (batch.length === batchSize) {
db.getSiblingDB('target_database').getCollection(collectionName).insertMany(batch);
batch = [];
}
});
if (batch.length > 0) {
db.getSiblingDB('target_database').getCollection(collectionName).insertMany(batch);
}
print("集合 " + collectionName + " 迁移完成");
});
方法三:使用聚合管道(MongoDB 4.2+)
// 使用 $out 将数据写入到另一个数据库
use source_database
db.collection_name.aggregate([
{ $out: { db: "target_database", coll: "collection_name" } }
]);
方法四:使用 $merge(MongoDB 4.2+)
// 使用 $merge 合并数据到目标数据库
use source_database
db.collection_name.aggregate([
{
$merge: {
into: { db: "target_database", coll: "collection_name" },
whenMatched: "replace",
whenNotMatched: "insert"
}
}
]);
方法五:使用 Node.js 脚本
const { MongoClient } = require('mongodb');
async function migrateData() {
const client = new MongoClient('mongodb://localhost:27017');
await client.connect();
const sourceDb = client.db('source_database');
const targetDb = client.db('target_database');
// 获取所有集合
const collections = await sourceDb.listCollections().toArray();
for (const collection of collections) {
const collectionName = collection.name;
// 跳过系统集合
if (collectionName.startsWith('system.')) continue;
console.log(`正在迁移集合: ${collectionName}`);
const sourceCollection = sourceDb.collection(collectionName);
const targetCollection = targetDb.collection(collectionName);
// 使用流式处理大量数据
const cursor = sourceCollection.find();
const batch = [];
const batchSize = 1000;
await cursor.forEach(async (doc) => {
batch.push(doc);
if (batch.length === batchSize) {
await targetCollection.insertMany(batch);
batch.length = 0;
}
});
if (batch.length > 0) {
await targetCollection.insertMany(batch);
}
console.log(`集合 ${collectionName} 迁移完成`);
}
await client.close();
}
migrateData().catch(console.error);
迁移索引
如果需要同时迁移索引,可以使用以下脚本:
use source_database
db.getCollectionNames().forEach(function(collName) {
if (collName.startsWith('system.')) return;
// 获取索引信息
var indexes = db.getCollection(collName).getIndexes();
indexes.forEach(function(index) {
if (index.name === '_id_') return; // 跳过默认索引
var indexSpec = {};
var options = {};
// 构建索引规范
for (var field in index.key) {
indexSpec[field] = index.key[field];
}
// 设置索引选项
if (index.unique) options.unique = true;
if (index.sparse) options.sparse = true;
if (index.background) options.background = true;
if (index.name) options.name = index.name;
// 在目标数据库创建索引
db.getSiblingDB('target_database').getCollection(collName).createIndex(indexSpec, options);
});
});
验证迁移结果
// 验证文档数量
use source_database
var sourceCount = db.collection_name.countDocuments();
use target_database
var targetCount = db.collection_name.countDocuments();
print("源数据库文档数: " + sourceCount);
print("目标数据库文档数: " + targetCount);
print("迁移" + (sourceCount === targetCount ? "成功" : "失败"));
注意事项
- 备份数据:在迁移前请务必备份原始数据
- 索引迁移:上述方法主要迁移数据,索引需要单独处理
- 权限验证:如果启用了认证,需要添加相应的用户名和密码参数
- 性能考虑:对于大量数据,建议使用批量操作和适当的批次大小