You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Sails.js 1.x中基于sails-mongo创建与管理MongoDB索引的最佳方案

Hey there! Let's tackle this index management challenge with Sails.js 1.0 and MongoDB, since we can't rely on the old index model property or the unmaintained sails-hook-mongoat anymore. Below are practical, production-ready solutions for both your deployment scenarios:


1. New Deployment: Automatically Create Indexes on App Startup

The cleanest approach here is to build a custom Sails hook that runs when your app boots up, reads index configurations from your models, and creates them using MongoDB's native API.

Step 1: Define Index Configs in Your Models

Add a custom indexes property to each model where you need indexes (supports all MongoDB index types, including reverse/descending ones):

// api/models/User.js
module.exports = {
  attributes: {
    email: { type: 'string', required: true },
    username: { type: 'string' },
    createdAt: { type: 'number', autoCreatedAt: true }
  },
  // Custom index configuration
  indexes: [
    { keys: { email: 1 }, options: { unique: true, background: true } },
    { keys: { username: 1 }, options: { sparse: true, background: true } },
    // Reverse index example
    { keys: { createdAt: -1 }, options: { background: true } }
  ]
};

The background: true option ensures index creation doesn't block your database during startup (critical for production).

Step 2: Build the Index Manager Hook

Create a new hook in api/hooks/index-manager/index.js to handle index creation on app lift:

module.exports = function defineIndexManagerHook(sails) {
  return {
    async initialize() {
      sails.log.info('Starting index management hook...');

      // Loop through all models to process indexes
      for (const modelName in sails.models) {
        const model = sails.models[modelName];
        if (!model.indexes) continue; // Skip models with no index config

        try {
          // Get the raw MongoDB collection for the model
          const collection = await model.getDatastore().manager.collection(model.tableName);
          
          // Create each defined index
          for (const indexConfig of model.indexes) {
            await collection.createIndex(indexConfig.keys, indexConfig.options);
            sails.log.info(`✅ Created index ${JSON.stringify(indexConfig.keys)} for model ${modelName}`);
          }
        } catch (err) {
          sails.log.error(`❌ Failed to create indexes for model ${modelName}:`, err);
        }
      }

      sails.log.info('Index management hook finished.');
    }
  };
};

This hook runs automatically when your Sails app starts, so all indexes will be created on first deployment.


2. Deployment Updates: Migrate & Ensure Indexes Are Up-to-Date

For updates, you need to handle three scenarios: adding new indexes, updating existing index configurations, and removing unused old indexes. You can either extend the startup hook or build a standalone migration script.

Option A: Extend the Startup Hook for Incremental Updates

Modify the hook from above to compare existing indexes against your model configs, then update/clean up as needed:

// Inside the model loop in your index-manager hook
const collection = await model.getDatastore().manager.collection(model.tableName);
const existingIndexes = await collection.indexes();

// Convert existing index keys to a string format for easy comparison
const existingIndexKeys = existingIndexes.map(idx => 
  Object.keys(idx.key).map(k => `${k}_${idx.key[k]}`).join('_')
);

for (const indexConfig of model.indexes) {
  const indexKeyStr = Object.keys(indexConfig.keys).map(k => `${k}_${indexConfig.keys[k]}`).join('_');
  
  // Create missing indexes
  if (!existingIndexKeys.includes(indexKeyStr)) {
    await collection.createIndex(indexConfig.keys, indexConfig.options);
    sails.log.info(`✅ Created missing index ${indexKeyStr} for ${modelName}`);
  } else {
    // Update indexes if their configuration changed (e.g., unique/sparse flags)
    const existingIndex = existingIndexes.find(idx => 
      Object.keys(idx.key).map(k => `${k}_${idx.key[k]}`).join('_') === indexKeyStr
    );
    const needsUpdate = 
      existingIndex.unique !== (indexConfig.options?.unique || false) ||
      existingIndex.sparse !== (indexConfig.options?.sparse || false);

    if (needsUpdate) {
      sails.log.info(`🔄 Updating index ${indexKeyStr} for ${modelName}`);
      await collection.dropIndex(indexConfig.keys);
      await collection.createIndex(indexConfig.keys, indexConfig.options);
    } else {
      sails.log.info(`ℹ️ Index ${indexKeyStr} for ${modelName} is up to date`);
    }
  }
}

// Optional: Delete unused indexes (proceed with caution!)
for (const existingIndex of existingIndexes) {
  if (existingIndex.name === '_id_') continue; // Skip default _id index
  const idxKeyStr = Object.keys(existingIndex.key).map(k => `${k}_${existingIndex.key[k]}`).join('_');
  const isDesired = model.indexes.some(idx => 
    Object.keys(idx.keys).map(k => `${k}_${idx.keys[k]}`).join('_') === idxKeyStr
  );

  if (!isDesired) {
    sails.log.info(`🗑️ Dropping unused index ${idxKeyStr} for ${modelName}`);
    await collection.dropIndex(existingIndex.name);
  }
}

Option B: Standalone Migration Script

If you don't want index operations to slow down app startup, create a standalone script to run during deployment (e.g., via CI/CD):

// scripts/manage-indexes.js
const sails = require('sails');

// Lift Sails without starting HTTP/socket servers
sails.lift({
  hooks: { http: false, sockets: false, views: false },
  log: { level: 'info' }
}, async function(err) {
  if (err) {
    console.error('Failed to initialize Sails:', err);
    process.exit(1);
  }

  try {
    // Copy the index comparison/update logic from the hook here
    // ... (same code as the extended hook's model loop)

    console.log('✅ Index migration completed successfully');
    await sails.lower();
    process.exit(0);
  } catch (err) {
    console.error('❌ Index migration failed:', err);
    await sails.lower();
    process.exit(1);
  }
});

Run it during deployment with:

node scripts/manage-indexes.js

Key Notes for Production

  • Index Locking: Use background: true to avoid blocking database operations during index creation.
  • Unique Index Safety: Before creating unique indexes, ensure your existing data has no duplicates (otherwise creation will fail).
  • Permissions: Make sure your app's database user has createIndex and dropIndex permissions.
  • Low Peak Execution: For large collections, run index updates during low-traffic periods to minimize impact.

内容的提问来源于stack exchange,提问作者Gustavo Garcia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 10:08:59