MongoDB 重建索引
- 单机模式
- 集群模式或外置 MongoDB
- 
进入存储组件容器 docker exec -it $(docker ps | grep mingdaoyun-sc | awk '{print $1}') bash
- 登录 MongoDB 服务器(如果是副本集模式,则登录 PRIMARY 节点)
- 
创建 reIndex.js脚本文件,重建mdwsrows库下的用户自建索引reIndex.js脚本文件容var targetDbName = "mdwsrows"; // 目标数据库
 // 集合白名单,白名单中的集合不重建索引
 var collectionWhitelist = [
 "discussion",
 "rowrelations",
 "workSheetRowTopic",
 "workSheetTopic",
 "wslogs"
 ];
 // 索引白名单,白名单中的索引不重建
 var indexWhitelist = [
 "_id_",
 "idx_ctime",
 "idx_utime",
 "uk_rowid",
 "idx_tp_status",
 "idx_thirdprimary"
 ];
 // 格式化时间函数
 function formatDateTime() {
 var now = new Date();
 var utc8Time = new Date(now.getTime() + (8 * 60 * 60 * 1000));
 return utc8Time.toISOString().replace('Z', '+08:00');
 }
 // 格式化输出函数
 function printHeader(text) {
 print("\n" + "=".repeat(100));
 print(text);
 print("=".repeat(100));
 }
 function printSection(text) {
 print("\n" + "-".repeat(80));
 print(text);
 print("-".repeat(80));
 }
 function printTimedAction(time, action) {
 print(`\n[${time}] ${action}`);
 }
 // 格式化 JSON,保持一致的缩进
 function formatJSON(obj, indent = 5) {
 return JSON.stringify(obj, null, 2)
 .split('\n')
 .map((line, i) => i === 0 ? line : ' '.repeat(indent) + line)
 .join('\n');
 }
 // 格式化 createIndex 命令
 function formatCreateIndexCommand(collName, key, options) {
 return `db.${collName}.createIndex(${formatJSON(key)},\n ${formatJSON(options)})`;
 }
 function printCommand(command) {
 print(" └─ Execute:");
 print(" " + command);
 }
 function printCompletion(seconds) {
 print(` └─ ✓ Completed in ${seconds.toFixed(3)} seconds\n`);
 }
 // 连接到指定数据库
 var targetDb = db.getSiblingDB(targetDbName);
 var startTime = formatDateTime();
 printHeader("MongoDB Index Rebuild Process");
 print(`\n• Start Time: ${startTime}`);
 print(`• Target Database: ${targetDb.getName()}`);
 // 获取所有要重建所有的集 合(过滤集合白名单)
 var collections = targetDb.getCollectionNames().filter(function(collName) {
 return !collectionWhitelist.includes(collName) &&
 !collName.startsWith('system.');
 });
 print(`• Total Collections: ${collections.length}`);
 collections.forEach(function(collName, index) {
 var coll = targetDb.getCollection(collName);
 var stats = coll.stats();
 
 // 输出集合信息和进度
 printSection(`Processing Collection [${index + 1}/${collections.length}]: ${collName}`);
 print(`\n• Document Count: ${stats.count}`);
 print(`• Storage Size: ${stats.storageSize} bytes`);
 
 // 获取需要重建的索引(过滤索引白名单)
 var indexes = coll.getIndexes();
 var rebuildIndexes = indexes.filter(function(idx) {
 return !indexWhitelist.includes(idx.name);
 });
 
 if (rebuildIndexes.length === 0) {
 print("\n✓ No indexes need to be rebuilt.");
 return;
 }
 
 // 输出索引重建计划
 print(`\n• Indexes to Rebuild (${rebuildIndexes.length}):`);
 rebuildIndexes.forEach(function(idx) {
 print(` ├─ Name: ${idx.name.padEnd(20)}`);
 print(` │ Key: ${JSON.stringify(idx.key)}`);
 });
 
 // 重建每个索引
 rebuildIndexes.forEach(function(idx) {
 var key = idx.key;
 var options = {};
 
 // 复制索引配置(排除系统属性)
 for (var prop in idx) {
 if (!["v", "ns", "background"].includes(prop)) {
 options[prop] = idx[prop];
 }
 }
 options.background = true; // 后台构建索引
 
 try {
 // 删除旧索引
 var dropTime = formatDateTime();
 printTimedAction(dropTime, `Dropping Index: ${idx.name}`);
 printCommand(`db.${collName}.dropIndex("${idx.name}")`);
 
 var dropStart = new Date();
 coll.dropIndex(idx.name);
 var dropEnd = new Date();
 printCompletion((dropEnd - dropStart)/1000);
 
 // 创建新索引
 var createTime = formatDateTime();
 printTimedAction(createTime, `Creating Index: ${idx.name}`);
 printCommand(formatCreateIndexCommand(collName, key, options));
 
 var createStart = new Date();
 coll.createIndex(key, options);
 var createEnd = new Date();
 printCompletion((createEnd - createStart)/1000);
 
 } catch (e) {
 print(` └─ ✗ Error: ${e.message}`);
 print(" Skipping this index...\n");
 }
 });
 });
 var endTime = formatDateTime();
 printHeader("Process Completed");
 print(`\n• End Time: ${endTime}`);
- MongoDB 无认证
- MongoDB 有认证
- 
执行脚本 nohup mongo mongodb://127.0.0.1:27017/admin --quiet reIndex.js >> reIndex_output.log 2>&1 &- 执行日志会输出到 reIndex_output.log文件
 
- 执行日志会输出到 
- 
执行脚本 nohup mongo mongodb://root:password@127.0.0.1:27017/admin --quiet reIndex.js >> reIndex_output.log 2>&1 &- 如果 mongo命令没加入 PATH 变量,则需指定绝对路径
- 执行日志会输出到 reIndex_output.log文件
 
- 如果 
- 
观察日志,等待脚本执行完成即可(日志结尾会输出 Process Complete与End Time)
- 
创建 reIndexWithCmd.js脚本文件,重建部分 HAP 系统依赖索引reIndexWithCmd.js脚本文件容// ====================================================================
 // CONFIGURATION
 // ====================================================================
 // 在这里配置您需要重建索引的数据库及其白名单集合
 // 格式: "数据库名": ["要跳过的集合1", "要跳过的集合2..."]
 // 如果某个库下所有集合都需要重建索引,请使用空数组 []
 var targetDatabases = {
 "mdpost": [],
 "MDHistory": []
 };
 // ====================================================================
 // 格式化输出函数 (无需修改)
 function printHeader(text) {
 print("\n" + "=".repeat(100));
 print(text);
 print("=".repeat(100));
 }
 function printSection(text) {
 print("\n" + "-".repeat(80));
 print(text);
 print("-".repeat(80));
 }
 function formatDateTime() {
 var now = new Date();
 var utc8Time = new Date(now.getTime() + (8 * 60 * 60 * 1000));
 return utc8Time.toISOString().replace('Z', '+08:00');
 }
 function formatJSON(obj, indent = 5) {
 if (obj === undefined || obj === null) {
 return "Not available";
 }
 return JSON.stringify(obj, null, 2)
 .split('\n')
 .map((line, i) => i === 0 ? line : ' '.repeat(indent) + line)
 .join('\n');
 }
 function formatFileSize(bytes) {
 if (bytes === undefined || bytes === null) return "N/A";
 return (bytes / 1024 / 1024).toFixed(2) + " MB";
 }
 function printTimedAction(time, action) {
 print(`\n[${time}] ${action}`);
 }
 function printCompletion(seconds) {
 print(` └─ ✓ Completed in ${seconds.toFixed(3)} seconds\n`);
 }
 // ====================================================================
 // SCRIPT EXECUTION
 // ====================================================================
 var overallStartTime = formatDateTime();
 printHeader("MongoDB Multi-Database Index Rebuild Process Started");
 print(`\n• Overall Start Time: ${overallStartTime}`);
 print(`• Databases to Process: ${Object.keys(targetDatabases).join(', ')}`);
 // 遍历配置中的所有数据库
 for (var dbName in targetDatabases) {
 if (targetDatabases.hasOwnProperty(dbName)) {
 
 printHeader(`Processing Database: [ ${dbName} ]`);
 // 获取目标数据库连接
 var currentDb = db.getSiblingDB(dbName);
 
 // 获取当前数据库的集合黑名单(即需要跳过的集合列表)
 var excludedCollections = targetDatabases[dbName];
 print(`\n• Target Database: ${currentDb.getName()}`);
 print(`• Excluded Collections: ${formatJSON(excludedCollections)}`);
 // 获取所有集合
 var collections = currentDb.getCollectionNames();
 // 过滤掉黑名单中的集合和系统集合
 var validCollections = collections.filter(collection =>
 !excludedCollections.includes(collection) && !collection.startsWith('system.')
 );
 print(`• Total Collections to Process in this DB: ${validCollections.length}`);
 
 if (validCollections.length === 0) {
 print("\nNo collections to process in this database. Moving to the next one.");
 continue;
 }
 validCollections.forEach(function(collection, index) {
 try {
 // 获取集合统计信息
 var stats = currentDb[collection].stats();
 
 // 输出集合信息和进度
 printSection(`Processing Collection [${index + 1}/${validCollections.length}]: ${collection}`);
 print(`\n• Collection Statistics:`);
 print(` ├─ Storage Size: ${formatFileSize(stats.storageSize)}`);
 print(` └─ Document Count: ${(stats.count || 0).toLocaleString()}`);
 
 // 获取当前索引信息
 var indexes = currentDb[collection].getIndexes();
 print(`\n• Current Indexes (${indexes.length}):`);
 indexes.forEach(function(idx, i) {
 const isLast = i === indexes.length - 1;
 print(` ${isLast ? '└' : '├'}─ Name: ${idx.name.padEnd(20)}`);
 print(` ${isLast ? ' ' : '│'} Key: ${formatJSON(idx.key)}`);
 });
 
 // 执行 reIndex
 var execTime = formatDateTime();
 printTimedAction(execTime, "Executing reIndex()");
 print(" └─ Execute:");
 print(` db.getSiblingDB('${dbName}').getCollection('${collection}').reIndex()`);
 
 var startExec = new Date();
 var result = currentDb[collection].reIndex();
 var endExec = new Date();
 
 if (result.ok === 1) {
 printCompletion((endExec - startExec)/1000);
 
 print("• Operation Results:");
 print(` ├─ Previous Index Count: ${result.nIndexesWas}`);
 print(` ├─ Current Index Count: ${result.nIndexes}`);
 
 if (result.operationTime !== undefined) {
 print(` ├─ Operation Time: ${formatJSON(result.operationTime)}`);
 } else {
 print(` ├─ Operation Time: Not available (non-replica set deployment)`);
 }
 
 if (result.$clusterTime !== undefined) {
 print(` └─ Cluster Time: ${formatJSON(result.$clusterTime)}`);
 } else {
 print(` └─ Cluster Time: Not available (non-replica set deployment)`);
 }
 
 } else {
 print(` └─ ✗ ReIndex failed: ${formatJSON(result)}`);
 }
 } catch (e) {
 print(` └─ ✗ Error: ${e.message}`);
 print(" Skipping this collection...\n");
 }
 });
 }
 }
 var overallEndTime = formatDateTime();
 printHeader("Process Completed");
 print(`\n• Overall End Time: ${overallEndTime}`);
- MongoDB 无认证
- MongoDB 有认证
- 
执行脚本 nohup mongo mongodb://127.0.0.1:27017/admin --quiet reIndexWithCmd.js >> reIndexWithCmd_output.log 2>&1 &- 执行日志会输出到 reIndexWithCmd_output.log文件
 
- 执行日志会输出到 
- 
执行脚本 nohup mongo mongodb://root:password@127.0.0.1:27017/admin --quiet reIndexWithCmd.js >> reIndexWithCmd_output.log 2>&1 &- 如果 mongo命令没加入 PATH 变量,则需指定绝对路径
- 执行日志会输出到 reIndexWithCmd_output.log文件
 
- 如果 
- 观察日志,等待脚本执行完成即可(日志结尾会输出 Process Complete与End Time)