Índices Parciais
Novo na versão 3.2.
Os índices parciais indexam apenas os documentos em uma collection que atendem a uma expressão de filtro especificada. Ao indexar um subconjunto de documentos em uma collection, os índices parciais têm requisitos de armazenamento mais baixos e custos de desempenho reduzidos para criação e manutenção de índices.
Criar um índice parcial
Para criar um índice partial
, use o método db.collection.createIndex()
com a opção partialFilterExpression
. A opção partialFilterExpression
aceita um documento que especifica a condição do filtro usando:
expressões de igualdade (ou seja,
field: value
ou usando o operador$eq
),$exists: true
expressão,$type
expressões,$and
operador apenas no nível superior
Por exemplo, a seguinte operação cria um índice composto que indexa somente os documentos com um campo rating
maior que 5.
db.restaurants.createIndex( { cuisine: 1, name: 1 }, { partialFilterExpression: { rating: { $gt: 5 } } } )
Você pode especificar uma opção partialFilterExpression
para todos os tipos de índiceMongoDB.
Comportamento
Cobertura de query
O MongoDB não utiliza o índice parcial para uma query ou operação de classificação se utilizar os resultados do índice em um conjunto de resultados incompleto.
Para usar o índice parcial, uma query deve conter a expressão de filtro (ou uma expressão de filtro modificada que especifica um subconjunto da expressão de filtro) como parte de sua condição.
Por exemplo, considerando o índice a seguir:
db.restaurants.createIndex( { cuisine: 1 }, { partialFilterExpression: { rating: { $gt: 5 } } } )
A query a seguir pode usar o índice, pois seu predicado inclui a condição rating: { $gte: 8 }
que corresponde a um subconjunto de documentos correspondentes à expressão de filtrorating: { $gt: 5
}
do índice:
db.restaurants.find( { cuisine: "Italian", rating: { $gte: 8 } } )
No entanto, a query a seguir não pode usar o índice parcial no campo cuisine
porque o uso do índice resulta em um conjunto de resultados incompleto. Especificamente, o predicado da query inclui a condição rating: { $lt: 8 }
, enquanto o índice tem o filtro rating: { $gt:
5 }
. Ou seja, a query { cuisine: "Italian", rating: { $lt: 8 }
}
corresponde a mais documentos (por exemplo, um restaurante italiano com uma classificação igual a 1) do que os indexados.
db.restaurants.find( { cuisine: "Italian", rating: { $lt: 8 } } )
Da mesma forma, a query a seguir não pode usar o índice parcial porque o predicado da query não inclui a expressão de filtro e o uso do índice retornaria um conjunto de resultados incompleto.
db.restaurants.find( { cuisine: "Italian" } )
Comparação com índices esparsos
Os índices parciais são preferidos em relação aos índices esparsos. Os índices parciais fornecem os seguintes benefícios:
Maior controle de quais documentos são indexados.
Um superconjunto da funcionalidade oferecida pelos índices esparsos.
Índices esparsos selecionam documentos para indexar somente com base na existência do campo indexado ou, para índices compostos, na existência dos campos indexados.
Os índices parciais determinam as entradas de índice com base no filtro especificado. O filtro pode incluir campos diferentes das chaves de índice e pode especificar condições diferentes de apenas uma verificação de existência. Por exemplo, um índice parcial pode implementar o mesmo comportamento de um índice esparso:
db.contacts.createIndex( { name: 1 }, { partialFilterExpression: { name: { $exists: true } } } )
Este índice parcial suporta as mesmas queries que um índice esparso no campo name
.
No entanto, um índice parcial também pode especificar expressões de filtro em campos diferentes da chave de índice. Por exemplo, a seguinte operação cria um índice parcial, no qual o índice está no campo name
, mas a expressão de filtro está no campo email
:
db.contacts.createIndex( { name: 1 }, { partialFilterExpression: { email: { $exists: true } } } )
Para que o otimizador de queries escolha esse índice parcial, o predicado da query deve incluir uma condição no campo name
, bem como uma correspondência não nula no campo email
.
Por exemplo, a query a seguir pode usar o índice porque inclui uma condição no campo name
e uma correspondência não nula no campo email
:
db.contacts.find( { name: "xyz", email: { $regex: /\.org$/ } } )
No entanto, a query a seguir não pode usar o índice porque inclui uma correspondência nula no campo email
, o que não é permitido pela expressão de filtro { email: { $exists: true } }
:
db.contacts.find( { name: "xyz", email: { $exists: false } } )
Índices TTL parciais
Os índices parciais também podem ser índices TTL. Os índices TTL parciais correspondem à expressão do filtro especificada e expiram apenas esses documentos. Para obter detalhes, consulte Expirar documentos com condições de filtro.
Restrições
A partir do MongoDB 5.0, vários índices parciais podem ser criados usando o mesmo padrão de chave, desde que os campos partialFilterExpression não expressem filtros equivalentes.
Nas versões anteriores do MongoDB, a criação de vários índices parciais não é permitida ao usar o mesmo padrão de chave com diferentes PartialFilterExpressions.
Você não pode especificar a opção partialFilterExpression
e a opção sparse
.
_id
os índices não podem ser índices parciais.
Os índices de chave de shard não podem ser índices parciais.
Exemplos
Criar um índice parcial em uma collection
Considere uma collection restaurants
contendo documentos que se assemelham ao seguinte
{ "_id" : ObjectId("5641f6a7522545bc535b5dc9"), "address" : { "building" : "1007", "coord" : [ -73.856077, 40.848447 ], "street" : "Morris Park Ave", "zipcode" : "10462" }, "borough" : "Bronx", "cuisine" : "Bakery", "rating" : { "date" : ISODate("2014-03-03T00:00:00Z"), "grade" : "A", "score" : 2 }, "name" : "Morris Park Bake Shop", "restaurant_id" : "30075445" }
Você pode adicionar um índice parcial nos campos borough
e cuisine
escolhendo somente para indexar documentos onde o campo rating.grade
é A
:
db.restaurants.createIndex( { borough: 1, cuisine: 1 }, { partialFilterExpression: { 'rating.grade': { $eq: "A" } } } )
Em seguida, a seguinte query na collection restaurants
utiliza o índice parcial para retornar os restaurantes no Bronx com rating.grade
igual a A
:
db.restaurants.find( { borough: "Bronx", 'rating.grade': "A" } )
No entanto, a seguinte query não pode utilizar o índice parcial porque a expressão de query não inclui o campo rating.grade
:
db.restaurants.find( { borough: "Bronx", cuisine: "Bakery" } )
Índice parcial com restrição única
Os índices parciais indexam apenas os documentos em uma collection que atendem a uma expressão de filtro especificada. Se você especificar a partialFilterExpression
e uma restrição exclusiva, esta só se aplicará aos documentos que atenderem à expressão de filtro. Um índice parcial com uma restrição exclusiva não impede a inserção de documentos que não atendem à restrição exclusiva se os documentos não atenderem aos critérios do filtro.
Por exemplo, uma collection users
contém os seguintes documentos:
{ "_id" : ObjectId("56424f1efa0358a27fa1f99a"), "username" : "david", "age" : 29 } { "_id" : ObjectId("56424f37fa0358a27fa1f99b"), "username" : "amanda", "age" : 35 } { "_id" : ObjectId("56424fe2fa0358a27fa1f99c"), "username" : "rajiv", "age" : 57 }
A seguinte operação cria um índice que especifica uma restrição exclusiva no campo username
e uma expressão de filtro parcial age: { $gte: 21 }
.
db.users.createIndex( { username: 1 }, { unique: true, partialFilterExpression: { age: { $gte: 21 } } } )
O índice impede a inserção dos seguintes documentos, pois já existem documentos com os nomes de usuário especificados e os campos age
são maiores que 21
:
db.users.insertMany( [ { username: "david", age: 27 }, { username: "amanda", age: 25 }, { username: "rajiv", age: 32 } ] )
No entanto, os seguintes documentos com nomes de usuário duplicados são permitidos, pois a restrição exclusiva só se aplica a documentos com age
maior ou igual a 21.
db.users.insertMany( [ { username: "david", age: 20 }, { username: "amanda" }, { username: "rajiv", age: null } ] )