《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 }

相关内容

热门资讯

威宁富民村镇银行:开展“助老清... 近日,威宁富民村镇银行星火义工队前往双龙镇凉山村,开展“助老清洁以爱暖冬”公益活动,为村中生活困难的...
王楚钦因伤退赛!WTT总决赛男... 图源:新华社 北京时间12月14日,WTT香港总决赛男单半决赛,中国选手王楚钦对阵瑞典选手莫雷加德。...
锦波生物大宗交易成交478.8... 锦波生物(920982)12月12日大宗交易平台出现一笔成交,成交量1.46万股,成交金额478.8...
多名基金经理热议跨年布局:科技... 2025年全年,科技股成为市场的主要驱动力,而其他板块如新旧消费、公共设施和房地产等表现不佳,多只个...
价格大跳水!上万元买进,现在只... 近年来 培育钻石价格持续走低 如今1克拉培育钻石价格 已从8000元跌至3500元 不及同等品质天然...
年内公募基金自购权益类基金相较... 今年以来,公募基金机构通过自购行动展现对市场的信心。截至12月11日,公募基金自购权益类基金的净申购...
万科20亿元境内债的三份展期议... 这笔债券还有五个工作日的宽限期,若在宽限期内未能与债权人达成共识,万科将构成实质性违约 文|《财经》...
24岁创二代,成为韵达股份独董... 每经编辑|杜宇 12月13日,韵达股份(SZ002120)发布关于董事会换届选举的公告。 公告称,...
捅向怡合达的“两把剑”:连遭高... 深圳商报·读创客户端记者 宁可坚 年内频遭股东抛售的怡合达(301029),出现在了创业板指数样本股...
邮储银行招标结果:中国邮政储蓄... 证券之星消息,根据天眼查APP-财产线索数据整理,中国邮政储蓄银行股份有限公司12月11日发布《中国...
中信银行深化小微融资协调机制,... 自支持小微企业融资协调工作机制建立以来,中信银行践行金融工作的政治性、人民性,通过“五专五强化”工作...
中远海运特运、中远海运西亚、P... 项目二期建成后,将控制10万平米的核心供应链资源,为中远海运特运多用途船、半潜船、汽车船等专业船队,...
原创 金... 12月8日,一个值得载入金融史册的日子。 这一天,现货黄金价格年内涨幅逼近60%,而标普500指数也...
上任11天,睿智医药董秘高莹莹... 红星资本局12月14日消息,睿智医药(300149.SZ)90后董事会秘书高莹莹上任仅11天后,递交...
美股点金丨市场波动率再升温!年... 上周美股三大指数走势分化,尾盘跳水将衡量市场波动性的恐慌指数推高近20%。 甲骨文与博通的季度业绩凸...
同益股份:邵羽南累计质押股数为... 每经AI快讯,同益股份(SZ 300538,收盘价:16.37元)12月12日晚间发布公告称,截至本...
演员何晴去世,享年61岁 12月13日,一份家属发布讣告显示,著名演员何晴在北京安然离世,享年61岁。告别仪式将于2025年1...
吉林省集安益盛药业股份有限公司... 本公司及董事会全体成员保证信息披露内容的真实、准确和完整,没有虚假记载、误导性陈述或重大遗漏。 吉林...
月内暂停投放所有茅台产品?第三... 近日,市场盛传茅台启动了年底控量“新政”:2025年12月内暂停向经销商发放所有茅台产品,直至202...