loading...
Cover image for Wildcard Indexes com MongoDB 4.2

Wildcard Indexes com MongoDB 4.2

delbussoweb profile image Leandro Domingues ・3 min read

Fala pessoALL, aproveitando a liberação da versão GA do MongoDB 4.2, vou mostrar um pouquinho de um dos recursos que achei bem interessantes para na questão de modelagem e performance, um novo tipo de índice: o Wildcard index.

Como o MongoDB suporta um schemas dinâmicos, nossas aplicações podem fazer queries utilizando campos onde os nomes desses campos sejam desconhecidos ou até mesmo em campos opcionais. Até a versão 4.0 nós tínhamos duas maneiras de fazer isso: criando um índice para cada um desses campos, porém, precisávamos conhecer cada um deles, ou criar algo parecido com um dicionário com chaves e valores, o que ficaria "feio" e parecido com isso:

{
  "k": "nome do atributo",
  "v": "valor do atributo"
}

O Wildcard Index vem pra nos auxiliar quando temos tanto campos com schema "fixo", ou o que eu acho mais bacana, quando temos campos com schema dinâmico. Vou dar um exemplo de com a base de candidatos de eleições no Brasil e fazer alguns testes de performance utilizando esse tipo de índice. Vejamos um exemplo de documento:

{
    "_id" : ObjectId("5d126803044a9b1399ba41e7"),
    "personalInformation" : {
        "maritalStatus" : [ 
            {
                "year" : 2018,
                "code" : 1,
                "description" : "SOLTEIRO(A)"
            }
        ],
        "schooling" : [ 
            {
                "year" : 2018,
                "code" : 8,
                "description" : "SUPERIOR COMPLETO"
            }
        ],
        "emailAddresses" : [ 
            {
                "year" : 2018,
                "email" : "gpm.guimaraes.adv@gmail.com"
            }
        ],
        "birth" : {
            "date" : ISODate("1987-04-13T00:00:00.000Z"),
            "city" : "RIO DE JANEIRO",
            "cityCode" : -3,
            "state" : "RJ"
        },
        "voterRegistration" : "133364270353",
        "nationality" : "BRASILEIRA NATA",
        "occupation" : [ 
            {
                "year" : 2018,
                "code" : 257,
                "description" : "EMPRESARIO"
            }
        ],
        "name" : "HIPOLITO LUIS NUNEZ DOMARCO NETO",
        "gender" : "MASCULINO",
        "race" : "BRANCA",
        "document" : "09866446760",
        "socialName" : "#NULO#"
    },
    "electionInformation" : [ 
        {
            "year" : 2018,
            "state" : "RJ",
            "role" : {
                "code" : 6,
                "description" : "DEPUTADO FEDERAL"
            },
            "politicalParty" : {
                "legend" : "PMN / AVANTE",
                "number" : 70,
                "name" : "AVANTE",
                "legendComposition" : [ 
                    "PMN", 
                    "AVANTE"
                ],
                "initials" : "AVANTE"
            },
            "candidateNumber" : 7015,
            "situation" : "APTO",
            "age" : 31,
            "nameExibition" : "HIPLITO DOMARCO"
        }
    ]
}

O atributo electionInformation é um array que pode armazenar várias eleições onde o candidato participou, e tem vários atributos que podem ser utilizados para fazer qualquer tipo de pesquisa. Por exemplo, se quisermos exibir todos os candidatos que fazem parte de um determinado Partido:

db.candidates.find({
    "electionInformation.politicalParty.initials":"AVANTE"
})

Executando essa consulta teríamos o seguinte plano de execução:

Alt Text

Na imagem acima temos algumas informações importantes sobre nossa query. A primeira delas é que como não temos um índice o jeito foi fazer um COLLSCAN, nesse caso o MongoDB teve que examinar cada um dos 7.651 documentos da coleção para retornar apenas 398 resultados e essa operação levou 8ms. E o MongoDB Compass nos sinalizou que não existe um índice para suportar essa query.

Agora vamos criar um índice do tipo Wildcard e ver como nosso plano de execução se comporta:

db.candidates.createIndex(
    { "electionInformation.$**" : 1 } 
)

Executando a mesma query, temos o seguinte plano de execução:

Alt Text

Bem melhor, né?! Agora o MongoDB conseguiu utilizar o índice criado e executou a query em 0ms! Notem que os números de documentos examinados (Documents Examined) e documentos retornados (Documents Returned) são iguais e também condizem com o número de "entradas no índice" (Index Key Examined), isso significa que ele utilizou somente o índice pra satisfazer essa query, por isso ficou bem mais rápido!

"Ah Leandro, mas isso eu conseguiria fazer criando um índice específico para o atributo electionInformation.politicalParty.initials. Onde o Wildcard entra nisso?"

Sim, um índice específico resolveria, mas lembra do início do post, podemos não saber quais atributos existem, ou não criar índices para cada um desses atributos, logo, podemos fazer uma query por outro atributo existente:

db.candidates.find({
     "electionInformation.role.description":"DEPUTADO FEDERAL"
})

O MongoDB utilizará o mesmo índice:

Alt Text

Viu só? Isso, como eu disse, facilita muito em casos de schema dinâmico e também na manutenção dos índices! Claro que existem considerações e restrições que devem ser observadas, mais informações sobre o Wildcard Index você encontra aqui.

Se quiser testar esse novo tipo de índice e não tem o MongoDB 4.2 instalado, utilize o MongoDB Atlas, lá você pode criar um Replica Set para testes totalmente free!

Também se quiser ter um overview sobre algumas das principais novidades da versão 4.2, dê uma olhada aqui.

É isso, espero que tenham gostado e fiquem à vontade para comentar e compartilhar!

Um abraço e até mais!

Discussion

pic
Editor guide
Collapse
4ndr profile image
Andre

Muito bom artigo, não conhecia esse tipo de índice.
No caso é indexado todos os campos em "electionInformation"?

Collapse
delbussoweb profile image
Leandro Domingues Author

Exatamente André... isso também é muito legal para sub-documentos que não tem a mesma estrutura de atributos!

Collapse
4ndr profile image
Andre

Muito útil, obrigado pela infomação.