【问题标题】:Checking if an Index exists in mongodb检查MongoDB中是否存在索引
【发布时间】:2016-05-03 08:08:24
【问题描述】:

是否有我可以通过 mongo shell 中的 javascript 使用的命令来检查特定索引是否存在于我的 mongodb 中。我正在构建一个将创建索引的脚本文件。我希望如果我多次运行此文件,则不会重新创建已经存在的索引。

我可以使用 db.collection.getIndexes() 来获取我的数据库中所有索引的集合,然后构建一个逻辑来忽略已经存在的那些但我想知道是否有命令来获取索引然后忽略创建索引的脚本。比如:

If !exists(db.collection.exists("indexname")) 
{
    create  db.collectionName.CreateIndex("IndexName")
}

【问题讨论】:

  • 在索引已经存在时调用createIndex是一个空操作,所以真的不需要检查。
  • ensureIndex in mongodb的可能重复
  • @JohnnyHK:如果您没有写权限,这不是无操作。在这种情况下,代码将抛出错误not authorized to execute command { insert: "system.indexes" ...,而不是静默失败。

标签: mongodb


【解决方案1】:

我在 c# 中创建了一个自定义方法来检查索引是否存在,使用 mongo 驱动程序:

    public async Task<bool> ExistIndex(string indexName)
    {
        var indexes = _collection.Indexes.List().ToList();

        var indexNames = indexes
            .SelectMany(index => index.Elements)
            .Where(element => element.Name == "name")
            .Select(name => name.Value.ToString());
        
        if (indexNames.Contains(indexName))
            return true;

        return false;
    }

PS。 _collection 是我来自 mongo.driver 的 IMongoCollection

【讨论】:

    【解决方案2】:

    使用nodeJS MongoDB驱动2.2版:

    
    const MongoClient = require('mongodb').MongoClient;
    
    exports.dropOldIndexIfExist = dropOldIndexIfExist;
    async function dropOldIndexIfExist() {
      try {
        const mongoConnection = MongoClient.connect('mongodb://localhost:27017/test');
        const indexName = 'name_1';
        const isIndexExist = await mongoConnection.indexExists(indexName);
        if (isIndexExist === true) {
          await mongoConnection.dropIndex(indexName);
        }
      } catch (err) {
        console.error('dropOldIndexIfExist', err.message);
        throw err;
      }
    }
    

    【讨论】:

      【解决方案3】:

      在我的情况下,我做了如下。

         DBCollection yourcollectionName = mt.getCollection("your_collection");
          if (yourcollectionName.getIndexInfo() == null || yourcollectionName.getIndexInfo().isEmpty()) {         
            DBObject indexOptions = new BasicDBObject();
            indexOptions.put("pro1", 1);
            indexOptions.put("pro2", 1);       
            yourcollectionName.createIndex(indexOptions, "name_of_your_index", true);
           }
      

      【讨论】:

        【解决方案4】:

        在 MongoDB 中创建索引是一种幂等操作。因此,运行 db.names.createIndex({name:1}) 只会在索引不存在时创建索引。

        createIndex() 的已弃用(从 MongoDB 3.0 开始)别名是 ensureIndex(),这对 @987654327 的含义更加清晰@ 确实如此。


        编辑: 感谢 ZitRo 在 cmets 中澄清使用相同名称但与现有索引不同的选项调用 createIndex() 将引发错误 MongoError: Index with name: **indexName** already exists with different options,如 this question 中所述。


        如果您有其他检查原因,则可以通过以下两种方式之一访问当前索引数据:

        1. 从 v3.0 开始,我们可以使用 db.names.getIndexes(),其中 names 是集合的名称。 Docs here
        2. 在 v3.0 之前,您可以访问 system.indexes 集合并将 find 设为 bri describes below

        【讨论】:

        • 请注意,我们可能会通过仅执行createIndex 来捕获MongoError: Index with name: **indexName** already exists with different options 错误。所以有时使用db.collection.getIndexes() 是有意义的。请参阅this question 了解更多信息。
        • 这个答案令人惊讶。我来到这里是因为createIndex 每次启动我的服务器(mongo 2.6)都需要 30 秒以上的时间。确定索引是否存在肯定不需要那么长时间?
        • @Thor84no 2.6 不使用createIndex,它使用ensureIndex docs.mongodb.com/v2.6/core/index-creation
        • 无论哪种方式,它都需要很长时间并且重新启动服务器并不会更快。在我的大集合上验证索引的存在比在我的小集合上花费更长的时间也是没有意义的......
        • 我发现collection.createIndex(DBObject("_ts" -&gt; 1), DBObject("expireAfterSeconds" -&gt; ttl))不是幂等的——如果过期值和已经使用的不同,就会失败。不过,也许这是这个 MongoDB 菜鸟偶然发现的特殊情况。
        【解决方案5】:

        也许我们可以使用https://docs.mongodb.com/v3.2/reference/method/db.collection.getIndexes/#db.collection.getIndexes 之类的东西来检查集合是否有一个等于某物的索引?

        如果是,则删除并添加新的或直接添加新的

        【讨论】:

          【解决方案6】:

          使用 db.system.indexes 并对其进行搜索。

          例如,如果您有一个名为“indexname”的索引,您可以像这样搜索它:

          db.system.indexes.find({'name':'indexname'});
          

          如果您需要在特定集合上搜索该索引,则需要使用 ns 属性(并且,拥有 db 名称会很有帮助)。

          db.system.indexes.find({'name':'indexname', 'ns':'dbname.collection'});
          

          或者,如果您绝对讨厌包含数据库名称...

          db.system.indexes.find({'name':'indexname', 'ns': {$regex:'.collection$'}});
          

          把它放在一起......

          所以,你完成检查将是:

          if(db.system.indexes.find({name:'indexname',ns:{$regex:'.collection$'}}).count()==0) { 
              db.collection.createIndex({blah:1},{name:'indexname'}) 
          }
          

          【讨论】:

          • 这在 3.4 版本上有效吗?我试过了,但它在控制台上什么也没返回。
          • @SohamShetty 自 v3.0 起已弃用。您现在应该使用db.name.getIndexes(),其中name 是您的集合的名称。
          猜你喜欢
          • 2021-07-22
          • 2012-11-30
          • 2015-09-16
          • 2015-02-13
          • 2013-05-28
          • 2010-09-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多