Índices Parciais
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,$or
operador,$in
operador, operador
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 índices do MongoDB. Ao especificar um partialFilterExpression
para um índice TTL em uma coleção de séries temporais, você só pode filtrar na coleção metaField
.
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
Você não pode especificar a opção
partialFilterExpression
e a opçãosparse
._id
os índices não podem ser índices parciais.Os índices de chave de shard não podem ser índices parciais.
Se você estiver utilizando o Client-Side Field Level Encryption ou o Queryable Encryption, um
partialFilterExpression
não poderá fazer referência a um campo criptografado.
Índices equivalentes
A partir do MongoDB 7.3, não é possível criar índices equivalentes, que são índices parciais com as mesmas chaves de índice e as mesmas expressões parciais que usam um agrupamento.
Para bancos de dados no MongoDB 7.3 com índices equivalentes existentes, os índices são retidos, mas somente o primeiro índice equivalente é usado nas consultas. Esse é o mesmo comportamento das versões MongoDB anteriores a 7.3.
Para obter um exemplo, consulte Exemplo de índices equivalentes.
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 query a seguir não pode usar o índice parcial porque o predicado da 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 } ] )
Exemplo de índices equivalentes
A partir do MongoDB 7.3, não é possível criar índices equivalentes, que são índices parciais com as mesmas chaves de índice e as mesmas expressões parciais que usam um agrupamento.
Para bancos de dados no MongoDB 7.3 com índices equivalentes existentes, os índices são retidos, mas somente o primeiro índice equivalente é usado nas consultas. Esse é o mesmo comportamento das versões MongoDB anteriores a 7.3.
Nas versões anteriores do MongoDB , você pode criar dois índices equivalentes. O exemplo seguinte cria uma coleção pizzas
e dois índices equivalentes denominados index0
e index1
:
// Create the pizzas collection db.pizzas.insertMany( [ { _id: 0, type: "pepperoni", size: "small", price: 4 }, { _id: 1, type: "cheese", size: "medium", price: 7 }, { _id: 2, type: "vegan", size: "large", price: 8 } ] ) // Create two equivalent indexes with medium pizza sizes db.pizzas.createIndex( { type: 1 }, { name: "index0", partialFilterExpression: { size: "medium" }, collation: { locale: "en_US", strength: 1 } } ) db.pizzas.createIndex( { type: 1 }, { name: "index1", partialFilterExpression: { size: "MEDIUM" }, collation: { locale: "en_US", strength: 1 } } )
Os índices são equivalentes porque os dois índices especificam o mesmo tamanho da pizza e diferem apenas nas maiúsculas e minúsculas do texto na expressão de filtro parcial . Somente um índice é usado pelas consultas: o índice que foi criado primeiro, que é index0
no exemplo anterior.
A partir do MongoDB 7.3, você não pode criar o segundo índice (index1
) e este erro é retornado:
MongoServerError: Index already exists with a different name: index0
Nas versões MongoDB anteriores a 7.3, você pode criar os índices, mas somente o primeiro índice (index0
) é usado com estas queries:
db.pizzas.find( { type: "cheese", size: "medium" } ).collation( { locale: "en_US", strength: 1 } ) db.pizzas.find( { type: "cheese", size: "MEDIUM" } ).collation( { locale: "en_US", strength: 1 } ) db.pizzas.find( { type: "cheese", size: "Medium" } ).collation( { locale: "en_US", strength: 1 } )