3 min read

AWS DocumnetDB匯出到社區版Mongodb

在遷移時遇到 DocumentDB 匯出時的*.metadata.json會有參雜獨有的參數,造成社區版匯入時的異常。

處理辦法

主要是透過 js 將所有metadata.json 裡面含有這段參數的都移除,就能順利透過mongorestore 匯入Mongodb。


為了快速啟用服務,這邊會使用Docker 。

docker run --name mongodb-temp -v ./:/temp mongo:5.0.31-focal

docker exec -it mongodb-temp bash

放入了些常用工具以及等等要運行的node 環境,可以進行一鍵安裝。

apt update
apt install zip unzip vim bash curl -y
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash
echo 'export NVM_DIR="$HOME/.nvm"' >> ~/.bashrc && echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm' >> ~/.bashrc
source ~/.bashrc
nvm install 20


匯出

#!/bin/bash

MONGO_HOST=""
MONGO_PORT="27017"
MONGO_USERNAME=""
MONGO_PASSWORD=""

mongodump --host=$MONGO_HOST \
          --port=$MONGO_PORT \
          --username=$MONGO_USERNAME \
          --password=$MONGO_PASSWORD

匯入

#!/bin/bash
#mongodb version 6

MONGO_USERNAME="root"
MONGO_PASSWORD=""
MONGO_AUTH_DB="admin"
MONGO_HOST=""
MONGO_PORT=""
TARGET_DB="xxx_db"
DUMP_PATH="./xxxx"

mongorestore --username=$MONGO_USERNAME \
             --password=$MONGO_PASSWORD \
             --authenticationDatabase=$MONGO_AUTH_DB \
             --nsInclude="$TARGET_DB.*" \
             --host=$MONGO_HOST \
             --port=$MONGO_PORT \
             $DUMP_PATH
#!/bin/bash
#mongodb version 5

MONGO_USERNAME="root"
MONGO_PASSWORD=""
MONGO_AUTH_DB="admin"
MONGO_HOST=""
MONGO_PORT=""
TARGET_DB="xxx_db"
DUMP_PATH="./xxxx"

mongorestore --username=$MONGO_USERNAME \
             --password=$MONGO_PASSWORD \
             --authenticationDatabase=$MONGO_AUTH_DB \
             --db=$TARGET_DB \
             --host=$MONGO_HOST \
             --port=$MONGO_PORT \
             $DUMP_PATH


js 移除meta數據源

node test.js dump/



const fs = require('fs');
const path = require('path');

/**
 * 修复DocumentDB导出的元数据文件以兼容MongoDB社区版
 * @param {string} directoryPath - 包含导出数据的目录路径
 */
function fixMetadataFiles(directoryPath) {
  console.log(`开始处理目录: ${directoryPath}`);
  
  // 递归遍历目录
  function processDirectory(dirPath) {
    const items = fs.readdirSync(dirPath);
    
    for (const item of items) {
      const itemPath = path.join(dirPath, item);
      const stats = fs.statSync(itemPath);
      
      if (stats.isDirectory()) {
        // 如果是目录,递归处理
        processDirectory(itemPath);
      } else if (stats.isFile() && item.endsWith('.metadata.json')) {
        // 如果是元数据文件,进行修复
        fixMetadataFile(itemPath);
      }
    }
  }
  
  // 修复单个元数据文件
  function fixMetadataFile(filePath) {
    console.log(`处理文件: ${filePath}`);
    
    try {
      // 读取元数据文件
      const content = fs.readFileSync(filePath, 'utf8');
      const metadata = JSON.parse(content);
      
      // 移除DocumentDB特有的设置
      if (metadata.options && metadata.options.storageEngine && 
          metadata.options.storageEngine.documentDB) {
        console.log(`  - 移除storageEngine设置`);
        delete metadata.options.storageEngine;
      }
      
      // 处理索引兼容性问题
      if (metadata.indexes && Array.isArray(metadata.indexes)) {
        let indexesFixed = false;
        
        metadata.indexes = metadata.indexes.map(index => {
          // 移除background选项
          if (index.background) {
            delete index.background;
            indexesFixed = true;
          }
          
          return index;
        });
        
        if (indexesFixed) {
          console.log(`  - 修复索引设置`);
        }
      }
      
      // 写回修复后的元数据
      fs.writeFileSync(filePath, JSON.stringify(metadata, null, 2));
      console.log(`  ✓ 文件已修复`);
    } catch (error) {
      console.error(`  ✗ 处理文件时出错: ${error.message}`);
    }
  }
  
  // 开始处理
  processDirectory(directoryPath);
  console.log('所有元数据文件处理完成');
}

// 如果直接运行此脚本
if (require.main === module) {
  // 获取命令行参数
  const args = process.argv.slice(2);
  
  if (args.length === 0) {
    console.error('错误: 请提供包含导出数据的目录路径');
    console.log('用法: node fix_metadata_files.js <导出目录路径>');
    process.exit(1);
  }
  
  const directoryPath = args[0];
  
  // 检查目录是否存在
  if (!fs.existsSync(directoryPath) || !fs.statSync(directoryPath).isDirectory()) {
    console.error(`错误: 目录 "${directoryPath}" 不存在或不是有效目录`);
    process.exit(1);
  }
  
  fixMetadataFiles(directoryPath);
}

module.exports = { fixMetadataFiles };