DEV Community

Cover image for Detectando índices no MongoDB
Leandro Domingues
Leandro Domingues

Posted on • Edited on

Detectando índices no MongoDB

Detecção de Índices

Será necessário?

Fala pessoALL, em algumas situações precisaremos identificar índices por algum motivo, seja para uma documentação do ambiente ou até mesmo para a reprodução desses índices em outro cluster, como por exemplo desenvolvimento, homologação ou até mesmo para colocá-los em produção. Ter um script que identifique estes índices é importante em vários sentidos e sempre bom tê-lo à mão.

No meu caso essa necessidade surgiu para efeito de documentação, principalmente para identificar se algumas coleções do banco de dados estavam com índices do tipo TTL, muito utilizados para o expurgo automático de dados.

Conectando

O cluster utilizado aqui está no MongoDB Atlas e se você não tem ainda um ambiente lá para testes pode criar um cluster totalmente free aqui.

Vamos utilizar o mongosh que é uma interface completa para administração do MongoDB, vou demonstrar passo-a-passo e por fim juntar tudo para criar o nosso script de saída. Também é importante ressaltar que os comandos à seguir foram executados na versão 7.0 do MongoDB.

mongosh "mongodb+srv://<seu_cluster>/myFirstDatabase" --apiVersion 1 --username <seu_usuario>
Enter fullscreen mode Exit fullscreen mode

Listando os databases

Aqui é importante ressaltar que o usuário utilizado para a conexão / execução do script deve ter os privilégios necessários para algumas tarefas, como listar os databases, coleções e por fim os índices. Veja mais sobre as permissões no MongoDB neste link.

var myDBs = db.adminCommand({ listDatabases: 1 }).databases.map(db => db.name);
myDBs.forEach(myDB => {
    print(myDB);
});
Enter fullscreen mode Exit fullscreen mode

Listando as coleções

Agora com os nomes dos databases de nosso cluster, podemos adicionar mais uma etapa e listar o nome das coleções de cada um deles. Note que não queremos listar as coleções dos databases admin e nem local, para isso, vamos adicionar uma condição que "exclua" esses databases.

var myDBs = db.adminCommand({ listDatabases: 1 }).databases.map(db => db.name);
myDBs.forEach(myDB => {
    if (myDB !== 'admin' && myDB !== 'local') {
        db = db.getSiblingDB(myDB);
        print(`Coleções no banco de dados ${myDB}:`);
        db.getCollectionNames().forEach(collectionName => {
            print(`- ${collectionName}`);
        });
    }
});
Enter fullscreen mode Exit fullscreen mode

Listando os índices

Agora, vamos finalmente listar os índices de cada uma das coleções:

var myDBs = db.adminCommand({ listDatabases: 1 }).databases.map(db => db.name);
myDBs.forEach(myDB => {
    if (myDB !== 'admin' && myDB !== 'local') {
        db = db.getSiblingDB(myDB);
        print(`Coleções no banco de dados ${myDB}:`);
        db.getCollectionNames().forEach(collectionName => {
            print(`- ${collectionName}`);
            let indexes = db.getCollection(collectionName).getIndexes();
            indexes.forEach(index => {
                print(`  - ${index.name} (${JSON.stringify(index)})`);
            });
        });
    }
});
Enter fullscreen mode Exit fullscreen mode

Note que para cada índice temos seu nome e também as propriedades que compõem cada um deles. Isso é importante não só para a identificação dessas propriedades, mas também para gerar uma saída para a criação de cada um deles.

Adicionando o createIndex()

Vamos modificar um pouco o script para que ele nos dê o comando para a criação de cada um desses índices:

var myDBs = db.adminCommand({ listDatabases: 1 }).databases.map(db => db.name);
myDBs.forEach(myDB => {
    if (myDB !== 'admin' && myDB !== 'local') {
        db = db.getSiblingDB(myDB);
        print(`Coleções no banco de dados ${myDB}:`);
        db.getCollectionNames().forEach(collectionName => {
            print(`- ${collectionName}`);
            let indexes = db.getCollection(collectionName).getIndexes();
            indexes.forEach(index => {
                print(`  - ${index.name} (${JSON.stringify(index)})`);
                print(`    -- create: db.getCollection("${collectionName}").createIndex(${JSON.stringify(index.key)}, ${JSON.stringify(index)});`)
            });
        });
    }
});
Enter fullscreen mode Exit fullscreen mode

Podemos também modificar um pouco mais para que o índice _id não gere o script para a criação:

var myDBs = db.adminCommand({ listDatabases: 1 }).databases.map(db => db.name);
myDBs.forEach(myDB => {
    if (myDB !== 'admin' && myDB !== 'local') {
        db = db.getSiblingDB(myDB);
        print(`Coleções no banco de dados ${myDB}:`);
        db.getCollectionNames().forEach(collectionName => {
            print(`- ${collectionName}`);
            let indexes = db.getCollection(collectionName).getIndexes();
            indexes.forEach(index => {
                if(index.name !== "_id_"){
                    print(`  - ${index.name} (${JSON.stringify(index)})`);
                    print(`    -- create: db.getCollection("${collectionName}").createIndex(${JSON.stringify(index.key)}, ${JSON.stringify(index)});`)
                }
            });
        });
    }
});
Enter fullscreen mode Exit fullscreen mode

Identificando uma propriedade do índice

Ok, chegamos até aqui, mas e se quisermos listar somente os índices com a propriedade TTL (como se deu a origem desse post)?

var myDBs = db.adminCommand({ listDatabases: 1 }).databases.map(db => db.name);
myDBs.forEach(myDB => {
    if (myDB !== 'admin' && myDB !== 'local') {
        db = db.getSiblingDB(myDB);
        print(`Coleções no banco de dados ${myDB}:`);
        db.getCollectionNames().forEach(collectionName => {
            print(`- ${collectionName}`);
            let indexes = db.getCollection(collectionName).getIndexes();
            indexes.forEach(index => {
                if(index.name !== "_id_"){
                    if (index.expireAfterSeconds !== undefined) {
                        print(`  - ${index.name} (${JSON.stringify(index)})`);
                        print(`    -- create: db.getCollection("${collectionName}").createIndex(${JSON.stringify(index.key)}, ${JSON.stringify(index)});`)
                    }
                }
            });
        });
    }
});
Enter fullscreen mode Exit fullscreen mode

Juntando tudo

Ufa, quanta coisa! Agora vamos juntar tudo para que nosso script seja realmente funcional em três pontos:

  • listar todos os índices (exceto o _id) de cada coleção de cada base de dados;
  • gerar o comando para a criação de cada um deles;
  • e por fim, somente os índices TTL. ### Todos os índices
var myDBs = db.adminCommand({ listDatabases: 1 }).databases.map(db => db.name);
myDBs.forEach(myDB => {
    if (myDB !== 'admin' && myDB !== 'local') {
        db = db.getSiblingDB(myDB);
        print(`use ${myDB};`);
        db.getCollectionNames().forEach(collectionName => {
            let indexes = db.getCollection(collectionName).getIndexes();
            indexes.forEach(index => {
                if (index.expireAfterSeconds !== undefined) {
                        printjson(`db.getCollection("${collectionName}").createIndex(${JSON.stringify(index.key)}, ${JSON.stringify(index)});`)
                }
            });
        });
    }
});
Enter fullscreen mode Exit fullscreen mode

Saída para arquivo

Aqui para facilitar, colocaremos o conteúdo de nosso script em um arquivo chamado verifyIndex.js, você pode criar esse arquivo como preferir. Com isso teremos um arquivo de saída chamado outputIndex.js.

  • crie o arquivo verifyIndex.js
cat << 'index' | tee verifyIndex.js
var myDBs = db.adminCommand({ listDatabases: 1 }).databases.map(db => db.name);
myDBs.forEach(myDB => {
    if (myDB !== 'admin' && myDB !== 'local') {
        db = db.getSiblingDB(myDB);
        print(`use ${myDB};`);
        db.getCollectionNames().forEach(collectionName => {
            let indexes = db.getCollection(collectionName).getIndexes();
            indexes.forEach(index => {
                if(index.name !== "_id_"){
                    printjson(`db.getCollection("${collectionName}").createIndex(${JSON.stringify(index.key)}, ${JSON.stringify(index)});`)
                }
            });
        });
    }
});
index
Enter fullscreen mode Exit fullscreen mode
  • carregue o arquivo utilizando o mongosh. Aqui utilizamos os seguintes parâmetros:
    • --file indicando o arquivo que será carregado
    • --quiet para que o arquivo de saída não contenha nenhum registro sobre a execução do mongosh, como abertura de conexão e etc.
    • e finalmente a saída será escrita no arquivo outputIndex.js
mongosh "mongodb+srv://<user>:<password>@<seu_cluster>/test" --file verifyIndex.js --quiet > outputIndex.js
Enter fullscreen mode Exit fullscreen mode

Saída para arquivo somente dos índices TTL

cat << 'index' | tee verifyIndex.js
myDBs.forEach(myDB => {
    if (myDB !== 'admin' && myDB !== 'local') {
        db = db.getSiblingDB(myDB);
        print(`use ${myDB};`);
        db.getCollectionNames().forEach(collectionName => {
            let indexes = db.getCollection(collectionName).getIndexes();
            indexes.forEach(index => {
                if (index.expireAfterSeconds !== undefined) {
                        printjson(`db.getCollection("${collectionName}").createIndex(${JSON.stringify(index.key)}, ${JSON.stringify(index)});`)
                }
            });
        });
    }
});
Enter fullscreen mode Exit fullscreen mode

Conclusão

É isso pessoALL... como sempre destaco em meus posts, existem diversas maneiras de fazer isso, uma delas é inclusive utilizando Python (o que particularmente eu gosto bastante), e prometo compartilhar o script mais a frente!

Espero que tenham gostado e fiquem à vontade para compartilhar!

Um abraço e até mais!

Top comments (0)