排除 MongoDB 通配符索引中的特定字段
在MongoDB中创建通配符索引时,您可以选择指定单个字段,所有字段或仅指定一些字段。
您还可以选择排除某些字段。换句话说,您可以指定除一个或多个特定字段_之外_的所有字段。
您可以使用该参数在通配符索引中包含或排除特定字段路径。本文提供了一个在通配符索引中排除特定字段的示例。wildcardProjection
示例文档
假设我们有一个包含以下文档的集合:pets
{ “_id” : 1, “name” : “Wag”, “details” : { “type” : “Dog”, “weight” : 20, “awards” : { “Florida Dog Awards” : “Top Dog”, “New York Marathon” : “Fastest Dog”, “Sumo 2020” : “Biggest Dog” } } } { “_id” : 2, “name” : “Fetch”, “details” : { “born” : ISODate(“2020-06-22T14:00:00Z”), “color” : “Black” } } { “_id” : 3, “name” : “Scratch”, “details” : { “eats” : [ “Mouse Porridge”, “Bird Soup”, “Caviar” ], “type” : “Cat”, “born” : ISODate(“2020-12-19T14:00:00Z”) } }
我们可以在整个集合上创建一个通配符索引,同时排除某些字段。
创建索引
下面是一个示例:
db.pets.createIndex(
{ "$**" : 1 },
{
"wildcardProjection" : {
"details.awards" : 0,
"details.eats" : 0
}
}
)
输出:
{ “createdCollectionAutomatically” : false, “numIndexesBefore” : 1, “numIndexesAfter” : 2, “ok” : 1 }
该部分是创建通配符索引的部分,该部分是指定要排除的字段的部分。在本例中,我们排除了字段和字段。为它们指定值 () 会将它们从索引中显式排除。{ "$**" : 1 }``wildcardProjection``details.awards``details.eats``0
查看索引
我们可以通过调用该方法查看集合上的索引:getIndexes()
db.pets.getIndexes()
结果:
[ { “v” : 2, “key” : { “_id” : 1 }, “name” : “id” }, { “v” : 2, “key” : { “$” : 1 }, “name” : “$_1”, “wildcardProjection” : { “details.awards” : 0, “details.eats” : 0 } } ]
我们可以看到有两个索引。
- 第一个索引在字段上。这是在创建集合时创建的(MongoDB在创建集合期间在_id字段上创建一个唯一的索引)。
_id - 第二个索引是我们的通配符索引。我们可以看到它已被自动命名,它包括我们指定的字段以及值 ,这意味着它们被明确排除在索引之外。
$**_1``0
测试索引
我们还可以运行一些查询来查看是否会使用我们的索引,以及是否真的会排除的字段。
以下查询应使用该索引:
db.pets.find( { "details.type" : "Dog" } )
它应该使用索引,因为我们没有从索引中排除该字段。details.type
为了测试这一点,我们可以附加方法来查看查询计划:explain()
db.pets.find( { "details.type" : "Dog" } ).explain()
结果:
{ “queryPlanner” : { “plannerVersion” : 1, “namespace” : “PetHotel.pets”, “indexFilterSet” : false, “parsedQuery” : { “details.type” : { “$eq” : “Dog” } }, “queryHash” : “F1C5286F”, “planCacheKey” : “5326DE93”, “winningPlan” : { “stage” : “FETCH”, “inputStage” : { “stage” : “IXSCAN”, “keyPattern” : { “$_path” : 1, “details.type” : 1 }, “indexName” : “$**_1”, “isMultiKey” : false, “multiKeyPaths” : { “$_path” : [ ], “details.type” : [ ] }, “isUnique” : false, “isSparse” : false, “isPartial” : false, “indexVersion” : 2, “direction” : “forward”, “indexBounds” : { “$_path” : [ “["details.type", "details.type"]” ], “details.type” : [ “["Dog", "Dog"]” ] } } }, “rejectedPlans” : [ ] }, “ok” : 1 }
我们可以看到它在我们的索引中使用了索引扫描(IXSCAN)。
与此相反,当我们对从索引中_排除_的字段之一运行查询时,会发生什么情况:
db.pets.find( { "details.awards.Florida Dog Awards" : "Top Dog" } ).explain()
结果:
{ “queryPlanner” : { “plannerVersion” : 1, “namespace” : “PetHotel.pets”, “indexFilterSet” : false, “parsedQuery” : { “details.awards.Florida Dog Awards” : { “$eq” : “Top Dog” } }, “queryHash” : “16FBC17B”, “planCacheKey” : “16FBC17B”, “winningPlan” : { “stage” : “COLLSCAN”, “filter” : { “details.awards.Florida Dog Awards” : { “$eq” : “Top Dog” } }, “direction” : “forward” }, “rejectedPlans” : [ ] }, “ok” : 1 }
在本例中,它执行了集合扫描(COLLSCAN),因此正如预期的那样,它没有使用索引。