《MongoDB入门教程》第30篇 唯一索引
创始人
2025-06-01 17:18:19
0

本文将会介绍 MongoDB 唯一索引,它可以用于确保文档字段值的唯一性。

唯一索引

很多时候我们需要确保文档中某个字段值的唯一性,例如 email 或者 username。唯一索引(unique index)可以帮助我们实现这种业务规则。实际上,MongoDB 使用唯一索引确保主键 _id 的唯一性。

创建唯一索引的方法和普通索引相同,只需要额外指定 {unique: true} 选项:

db.collection.createIndex({ field: 1}, {unique: true});

索引示例

首先,创建一个新的集合 users,插入一些文档:

db.users.insertMany([{ name: "张三", dob: "1990-01-01", email: "zhangsan@test.com"},{ name: "李四", dob: "1992-06-30", email: "lisi@test.com"}
]);

然后,我们基于 email 字段创建一个唯一索引:

db.users.createIndex({email:1},{unique:true});

接下来我们尝试插入一个已经存在的文档:

db.users.insertOne({ name: "张叁", dob: "1995-03-12", email: "zhangsan@test.com"}
);

此时,MongoDB 将会返回以下错误:

MongoServerError: E11000 duplicate key error collection: book.users index: email_1 dup key: { email: 'zhangsan@test.com' }

下面我们演示一下集合已经存在重复数据时如何创建唯一索引。首先删除并重建集合 users:

db.users.drop()db.users.insertMany([{ name: "张三", dob: "1990-01-01", email: "zhangsan@test.com"},{ name: "张叁", dob: "1995-03-12", email: "zhangsan@test.com"},{ name: "李四", dob: "1992-06-30", email: "lisi@test.com"}
]);

然后,基于 email 字段创建一个唯一索引:

db.users.createIndex({email: 1},{unique:true})MongoServerError: Index build failed: 95f78956-d5d0-4882-bfe0-2d856df18c61: Collection book.users ( 6da472db-2884-4608-98b6-95a003b4f29c ) :: caused by :: E11000 duplicate key error collection: mflix.users index: email_1 dup key: { email: zhangsan@test.com }

以上错误的原因在于 email 中存在重复的记录。

通常,我们会在插入数据之前创建唯一索引,可以从头开始确保数据的唯一性。如果基于已有数据创建唯一索引,可能会由于重复数据导致索引创建失败。为此,我们需要删除重复的数据之后再创建索引。

例如,我们可以首先删除重复的 user:

db.users.deleteOne({ name: "张叁", dob: "1995-03-12", email: "zhangsan@test.com"});{ acknowledged: true, deletedCount: 1 }

然后基于 email 字段创建唯一索引:

db.users.createIndex({email: 1},{unique:true})email_1

复合唯一索引

基于多个字段创建的唯一索引就是复合唯一索引(unique compound index)。复合唯一索引可以确保多个字段值的组合唯一。例如,基于字段 field1 和 field2 创建复合唯一索引,以下数据具有唯一性:

field1field2组合
11(1,1)
12(1,2)
21(2,1)
22(2,2)

以下数据存在重复值:

field1field2组合
11(1,1)
11(1,1) 重复
21(2,1)
21(2,1) 重复

接下来我们看一个示例,首先创建一个集合 locations。

db.locations.insertOne({address: "北京市丰台区莲花池东路118号北京西站",latitude: 39.894793,longitude: 116.321592
})

然后,基于 latitude 和 longitude 创建一个复合唯一索引:

db.locations.createIndex({latitude: 1,longitude: 1
},{ unique: true });'latitude_1_longitude_1'

插入一个经度相同的地点:

db.locations.insertOne({address: "北京市海淀区复兴路甲9号中华世纪坛",lat: 39.910577,long: 116.321592
})

操作执行成功,因为复合索引 latitude_1_longitude_1 校验的是经度和纬度的组合值。

最后,插入一个经纬度已经存在的地点:

db.locations.insertOne({address: "北京市丰台区莲花池东路118号北京西站",latitude: 39.894793,longitude: 116.321592
})

此时,MongoDB 返回重复键错误:

MongoServerError: E11000 duplicate key error collection: book.locations index: latitude_1_longitude_1 dup key: { lat: 39.894793, long: 116.321592 }

相关内容

热门资讯

青海:“五一”假期推出60余场... 中新网西宁5月6日电 (潘雨洁)记者6日从青海省商务厅获悉,“五一”假期,青海省各级商务部门、金融机...
银行业竞争逻辑正在经历一场变革 证券时报记者 马传茂 步入低利率时代,银行业关于“规模情结”的讨论持续发酵。一个耐人寻味的现象是:银...
基本面与新技术共振,锂电新周期... 5月国内电池排产达172.4GWh,环比增8%,同比猛增65%。另一边,钠电逻辑迎来里程碑:宁德时代...
曾是OpenAI前董事会成员!... 快科技5月7日消息,据媒体报道,日前,马斯克起诉了他的两位OpenAI联合创始人——CEO萨姆·奥特...
监护仪警报后,我们在做什么 杨明明 河北医科大学第一医院 在医院的病房、急诊室和ICU,监护仪的“滴滴”警报声是最常见的声音。很...
原创 美... 美股三大指数昨晚(当地时间5月5日)集体收涨,标普500和纳斯达克双双再创历史新高。 最惊人的一幕发...
华泰证券:地产板块估值筑底、配... 华泰证券研报指出,深圳、广州、武汉、苏州、济南等核心城市相继出台楼市优化政策,从公积金放宽、以旧换新...
第四批全国中成药联盟采购开标 ... 4月30日,第四批全国中成药联盟采购(以下简称“全国联采”)在武汉开标产生拟中选结果。本次集采纳入2...
跟踪800自由现金流的ETF有... 随着A股市场从估值修复转向盈利驱动,投资者对企业"真金白银"创造能力的关注度显著提升。自由现金流策略...
金价强势反弹,投资者怎么操作? 经历持续阴跌后,黄金市场迎来一轮强势反弹行情。 5月6日,国际金价短暂震荡后强势拉升。截至记者发稿,...
A股5月“开门红” 两市成交额... 科创50日K线图   张大伟 制图 ◎记者 费天元 5月首个交易日,A股主要股指全线上攻,盘面热点延...
首发|又一个核聚变独角兽:星环... 投资界获悉,星环聚能完成5亿元人民币A+轮融资,投资方阵容依旧豪华:包括达晨财智、金浦投资、上海申能...
为何翻倍提高CPU市场展望?苏... 财联社5月7日讯(编辑 史正丞)随着超威半导体(AMD)的最新财报再度唤起市场对CPU需求周期的关注...
“1页纸”让欧美亚股市大涨,油... 新华社援引美国媒体5月6日报称道,两名美国官员及另外两名知情人士透露,白宫认为,与伊朗接近达成一份一...
拟上市企业股权激励的注意事项 在企业的发展进程中,拟上市企业的股权激励是一个至关重要的环节。它不仅能够吸引和留住核心人才,还能激发...
5月7日每日研选丨基本面与新技... 5月国内电池排产达172.4GWh,环比增8%,同比猛增65%。另一边,钠电逻辑迎来里程碑:宁德时代...
美股收盘:纳指、标普再创新高 ... 财联社5月7日讯(编辑 史正丞)昨夜今晨,随着AI相关资产接力暴涨,标普500指数和纳斯达克指数连续...
美联储古尔斯比就通胀与消费者行... 芝加哥联邦储备银行行长奥斯滕・古尔斯比对通胀形势发出谨慎警示:美国通胀不仅未能持续回落至美联储 2%...
原创 北... 实验室里长出的,不只是论文还有独角兽。 又是一年五四,北大迎来了128岁生日。 未名湖畔的故事讲了...