Section 9.1: 创建索引基础知识

请参阅下面的事务集合。

> db.transactions.insert({ cr_dr : "D", amount : 100, fee : 2});
> db.transactions.insert({ cr_dr : "C", amount : 100, fee : 2});
> db.transactions.insert({ cr_dr : "C", amount : 10, fee : 2});
> db.transactions.insert({ cr_dr : "D", amount : 100, fee : 4});
> db.transactions.insert({ cr_dr : "D", amount : 10, fee : 2});
> db.transactions.insert({ cr_dr : "C", amount : 10, fee : 4});
> db.transactions.insert({ cr_dr : "D", amount : 100, fee : 2});

getIndexes() 函数将显示一个集合的所有可用索引。

db.transactions.getIndexes();

让我们看看上述语句的输出结果。

[
    {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "documentation_db.transactions"
    }
]

事务集合已有一个索引。这是因为 MongoDB 在创建集合时会在 _id 字段上创建唯一索引。_id 索引可防止客户端插入两个_id字段值相同的文档。您不能在 _id 字段上删除该索引。

现在,让我们为 cr_dr 字段添加一个索引;

db.transactions.createIndex({ cr_dr : 1 });

执行索引的结果如下。

{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}

createdCollectionAutomatically 表示操作是否创建了一个集合。如果不存在集合,MongoDB 会在索引操作中创建集合。

让我们再次运行 db.transactions.getIndexes();。

[
    {
        "v" : 1,
        "key" : {
                "_id" : 1
        },
        "name" : "_id_",
        "ns" : "documentation_db.transactions"
    },
    {
        "v" : 1,
        "key" : {
                "cr_dr" : 1
        },
        "name" : "cr_dr_1",
        "ns" : "documentation_db.transactions"
    }
]

现在你可以看到事务集合有两个索引。默认的 _id 索引和我们创建的 cr_dr_1。名称由 MongoDB 指定。你可以像下面这样设置自己的名称。

db.transactions.createIndex({ cr_dr : -1 },{name : "index on cr_dr desc"})

现在,db.transactions.getIndexes(); 将给出三个索引。

[
    {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
    "name" : "_id_",
    "ns" : "documentation_db.transactions"
    },
    {
        "v" : 1,
        "key" : {
                "cr_dr" : 1
        },
        "name" : "cr_dr_1",
        "ns" : "documentation_db.transactions"
    },
    {
        "v" : 1,
        "key" : {
                "cr_dr" : -1
        },
        "name" : "index on cr_dr desc",
        "ns" : "documentation_db.transactions"
    }
]

创建索引 { cr_dr : -1 } 时,1 表示索引将按升序排列,-1 表示按降序排列。

版本 ≥ 2.4

散列索引

索引也可以定义为散列索引。这对相等查询更有效,但对范围查询效率不高;不过,你可以在同一字段上定义散列索引和升序/降序索引。

> db.transactions.createIndex({ cr_dr : "hashed" });
> db.transactions.getIndexes(
[
    {
        "v" : 1,
        "key" : {
                "_id" : 1
        },
        "name" : "_id_",
        "ns" : "documentation_db.transactions"
    },
    {
        "v" : 1,
        "key" : {
                "cr_dr" : "hashed"
        },
        "name" : "cr_dr_hashed",
        "ns" : "documentation_db.transactions"
    }
]

Section 9.2: 放弃/删除索引

如果索引名称已知

db.collection.dropIndex('name_of_index');

如果不知道索引名称

db.collection.dropIndex( { 'name_of_field' : -1 } );

Section 9.3: 稀疏索引和部分索引

稀疏索引:

稀疏索引对于可选但也应是唯一的字段特别有用。

{ "_id" : "john@example.com", "nickname" : "Johnnie" }
{ "_id" : "jane@example.com" }
{ "_id" : "julia@example.com", "nickname" : "Jules"}
{ "_id" : "jack@example.com" }

由于有两个条目没有指定 “昵称”,而索引会将未指定的字段视为空,因此,如果有两个文档的 “昵称 ”为 “空”,索引创建就会失败:

db.scores.createIndex( { nickname: 1 } , { unique: true, sparse: true } )

会让你的昵称仍然为 “空”。

稀疏索引更紧凑,因为它们会跳过/忽略未指定该字段的文档。因此,如果你有一个只有不到 10%的文档指定了该字段的集合,你就可以创建更小的索引--如果你想进行以下查询,就能更好地利用有限的内存:

db.scores.find({'nickname': 'Johnnie'})

部分索引:

部分索引是稀疏索引所提供功能的超集,应优先于稀疏索引。(3.2 版新增)

部分索引根据指定的过滤器确定索引条目。

db.restaurants.createIndex(
    { cuisine: 1 },
    { partialFilterExpression: { rating: { $gt: 5 } } }
)

如果评分大于 5,那么菜肴将被索引。是的,我们也可以根据其他属性的值指定要索引的属性。

稀疏索引和部分索引的区别:

稀疏索引仅根据索引字段的存在来选择要索引的文档,对于复合索引,则根据索引字段的存在来选择要索引的文档。

部分索引根据指定的过滤器确定索引项。过滤器可以包括索引键以外的字段,也可以指定存在检查以外的条件。

尽管如此,部分索引仍可实现与稀疏索引相同的行为

例如

db.contacts.createIndex(
    { name: 1 },
    { partialFilterExpression: { name: { $exists: true } } }
)

注意:不能同时指定 partialFilterExpression 选项和 sparse 选项。

Section 9.4: 获取集合索引

db.collection.getIndexes();

输出结果

[
    {
        "v" : 1,
        "key" : {
                "_id" : 1
        },
        "name" : "_id_",
        "ns" : "documentation_db.transactions"
    },
    {
        "v" : 1,
        "key" : {
                "cr_dr" : 1
        },
        "name" : "cr_dr_1",
        "ns" : "documentation_db.transactions"
    },
    {
        "v" : 1,
        "key" : {
                "cr_dr" : -1
        },
        "name" : "index on cr_dr desc",
        "ns" : "documentation_db.transactions"
    }
]

Section 9.5: Compound

db.people.createIndex({name: 1, age: -1})

这会在多个字段上创建索引,本例中是在姓名和年龄字段上创建索引。索引将以姓名为升序,年龄为降序。

在这种类型的索引中,排序顺序非常重要,因为它将决定索引是否支持排序操作。复合索引的任何前缀都支持反向排序,只要排序中所有键的排序方向都是反向的。否则,复合索引的排序需要与索引的顺序相匹配。

字段顺序也很重要,在这种情况下,索引将首先按姓名排序,然后在每个姓名值内按年龄字段的值排序。这样就可以通过对姓名字段或姓名和年龄进行查询来使用该索引,但不能仅对年龄进行查询。

Section 9.6: 唯一索引

db.collection.createIndex( { "user_id": 1 }, { unique: true } )

对已定义的索引(单一索引或复合索引)强制执行唯一性。如果集合已包含重复值,建立索引将失败;如果多个条目缺少字段,建立索引也将失败(因为它们都将以空值建立索引),除非指定 sparse: true。

Section 9.7: 单个字段

db.people.createIndex({name: 1})

这会在字段名上创建一个升序单字段索引。

在这类索引中,排序顺序无关紧要,因为 mongo 可以双向遍历索引。

Section 9.8: 删除

要删除索引,可以使用索引名称

db.people.dropIndex("nameIndex")

或索引规范文件

db.people.dropIndex({name: 1})

Section 9.9: List

db.people.getIndexes()

这将返回一个文档数组,每个文档描述了人物集合的一个索引