【问题标题】:What is the recommended way to drop indexes using Mongoose?使用 Mongoose 删除索引的推荐方法是什么?
【发布时间】:2012-10-12 10:43:23
【问题描述】:

我需要为 MongoDB 数据库创建多个部署脚本,例如数据迁移和固定装置,但我找不到有关如何使用 Mongoose API 删除索引的足够信息。这在使用官方 MongoDB API 时非常简单:

删除指定集合上的所有索引:

db.collection.dropIndexes();

但是,我想为此使用 Mongoose,并尝试使用改编自 this postexecuteDbCommand,但没有成功:

mongoose.connection.db.executeDbCommand({ dropIndexes: collectionName, index: '*' },
  function(err, result) { /* ... */ });

我应该使用适用于 Node.js 的官方 MongoDB API 还是我在这种方法中遗漏了一些东西?

【问题讨论】:

  • 您在运行 executeDbCommand 代码时是否遇到错误?你的语法看起来有点不对劲,如果你运行 executeDbCommand({ dropIndexes: collectionName, index: '*'}, function(err,result) { ... }); ?我相信正确的语法是将完整的命令用大括号括起来,然后是函数。

标签: javascript node.js mongodb mongoose database


【解决方案1】:

这可能不是发布此内容的最佳位置,但我认为无论如何都值得发布。

每次针对数据库连接定义/创建模型时,我都会调用model.syncIndexes(),这可以确保索引是最新的并且与架构保持同步,但是因为它已在线突出显示(example),这可能会在分布式架构中产生问题,其中多个服务器同时尝试相同的操作。如果使用类似 cluster 库的东西在同一台机器上的多个内核上生成主/从实例,这一点尤其重要,因为当整个服务器启动时,它们通常会在彼此靠近的地方启动。

参考上面的“codebarbarian”文章,当他们声明时清楚地强调了这个问题:

Mongoose 不会为您调用 syncIndexes(),您需要负责 自己调用syncIndexes()。有几个原因, 最值得注意的是 syncIndexes() 不做任何类型的分布式 锁定。如果您有多个服务器调用 syncIndexes() 时 他们开始,你可能会因为试图删除一个索引而出错 已经不存在了。

所以我要做的是创建一个函数,它使用 redis 和 redis redlock 来获得一段时间的租约,以防止多个工作人员(实际上是多个服务器中的多个工作人员)同时尝试相同的同步操作.

它也绕过了整个事情,除非它是试图执行操作的“主人”,我认为将这项工作委派给任何工人没有任何实际意义。

const cluster               = require('cluster');
const {logger}              = require("$/src/logger");
const { 
    redlock, 
    LockError
}                           = require("$/src/services/redis");
const mongoose              = require('mongoose');

// Check is mongoose model, 
// ref: https://stackoverflow.com/a/56815793/1834057
const isMongoModel = (obj) => {
    return obj.hasOwnProperty('schema') && obj.schema instanceof mongoose.Schema;
}

const syncIndexesWithRedlock = (model,duration=60000) => new Promise(resolve => {

    // Ensure the cluster is master
    if(!cluster.isMaster) 
        return resolve(false)

    // Now attempt to gain redlock and sync indexes
    try {

        // Typecheck
        if(!model || !isMongoModel(model))
            throw new Error('model argument is required and must be a mongoose model');

        if(isNaN(duration) || duration <= 0)
            throw new Error('duration argument is required, and must be positive numeric')

        // Extract name
        let name        = model.collection.collectionName;

        // Define the redlock resource
        let resource    = `syncIndexes/${name}`;

        // Coerce Duration to Integer
        // Not sure if this is strictly required, but wtf. 
        // Will ensure the duration is at least 1ms, given that duration <= 0 throws error above
        let redlockLeaseDuration = Math.ceil(duration);

        // Attempt to gain lock and sync indexes
        redlock.lock(resource,redlockLeaseDuration)
            .then(() => {
                // Sync Indexes
                model.syncIndexes();

                // Success
                resolve(true);
            })
            .catch(err => {
                
                // Report Lock Error
                if(err instanceof LockError){
                    logger.error(`Redlock LockError -- ${err.message}`);

                // Report Other Errors
                }else{
                    logger.error(err.message);
                }

                // Fail, Either LockError error or some other error
                return resolve(false);
            })

    // General Fail for whatever reason
    }catch(err){
        logger.error(err.message);
        return resolve(false);
    }
});

我不会设置 Redis 连接,这是其他线程的主题,但上面这段代码的重点是展示如何可靠地使用 syncIndexes() 并防止一个线程删除索引而另一个线程出现问题尝试删除相同的索引,或尝试同时修改索引的其他分布式问题。

【讨论】:

    【解决方案2】:

    删除您可以使用的特定索引

    db.users.dropIndex("your_index_name_here")
    

    【讨论】:

    • OP 想要使用 mongoose - 虽然您可以通过 mongoose 获得这样的原生驱动程序代码,但这不是最简单或最直接的方法。
    【解决方案3】:

    如果您想使用 mongoose 维护架构定义中的索引(如果您使用的是 mongoose,您可能会这样做),您可以轻松删除不再使用的索引并创建尚不存在的索引。您可以在需要同步的任何型号上运行一个关闭await YourModel.syncIndexes()。它将使用.ensureIndexes 在后台创建一个,并删除架构定义中不再存在的任何内容。你可以在这里查看完整的文档: https://mongoosejs.com/docs/api.html#model_Model.syncIndexes

    【讨论】:

    • 对于来自 Google 搜索“Mongoose 删除重复索引”的人来说,这是理想的解决方案。它使用猫鼬 API 而不是公认的答案。
    • 这个解决方案看起来正是我想要的,也应该被接受的答案
    【解决方案4】:

    要通过集合的 Mongoose 模型执行此操作,您可以调用原生集合的 dropAllIndexes

    MyModel.collection.dropAllIndexes(function (err, results) {
        // Handle errors
    });
    

    更新

    dropAllIndexes 在本机驱动程序的 2.x 版本中已弃用,因此应使用 dropIndexes 代替:

    MyModel.collection.dropIndexes(function (err, results) {
        // Handle errors
    });
    

    【讨论】:

      【解决方案5】:

      您似乎正试图删除给定集合上的所有索引。

      根据 MongoDB 文档,this is the correct command

      ...我尝试使用改编自这篇文章的 executeDbCommand,但没有成功:

      要真正提供帮助,我们需要更多详细信息:

      • 什么失败了?您如何衡量“不成功”?
      • 您能否确认 100% 命令已运行?您是否在回调中输出到日志?您检查了err 变量吗?
      • 您在哪里创建索引?你能确认你没有在掉落后重新创建它们吗?
      • 您是否在列出特定索引名称时尝试过该命令?老实说,你不应该使用"*"。您应该删除并创建非常具体的索引。

      【讨论】:

      • “没有成功”是指代码执行没有任何错误,但我提供的回调从未被调用。我在一个小脚本中遇到了这个问题,它的唯一职责是删除和创建某些集合,包括它们的关联索引,并用一些测试所需的数据填充这些集合。
      猜你喜欢
      • 1970-01-01
      • 2012-02-27
      • 1970-01-01
      • 2019-09-15
      • 1970-01-01
      • 2021-11-16
      • 2010-10-19
      • 1970-01-01
      • 2019-04-05
      相关资源
      最近更新 更多