对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。

在非分片键的字段上强制唯一性

如果无法使用唯一字段作为分片键,或者需要实施多个字段的唯一性,请创建另一个集合以充当代理集合。

仅当唯一索引位于分片键上或包含分片键作为前缀时,分片集群才会跨分片实施唯一约束。代理集合可以绕过该限制:代理集合包含对原始文档的引用和唯一键,并且您的应用程序会首先写入代理集合。

使用代理集合时,请考虑以下事项:

  • 在将文档插入代理集合时,应用程序必须捕获错误。写入ACID 事务中的两个集合,以便在任一插入失败时,集合都不会出现分歧。

  • 如果代理集合需要分片,则必须对要强制唯一性的单个字段进行分片。

  • 每个字段都需要自己的代理集合。要使用分片的代理集合实施多个字段的唯一性,必须为每个字段设置一个代理集合。如果在单个代理集合上创建多个唯一索引,则无法对代理集合分片。

  • 这种方法需要在应用程序中生成 _id 值,而不是让MongoDB在插入文档时自动创建值,以便两个文档股票相同的 _id。

有关应用于分片的片集合上唯一索引的完整约束设立,请参阅在分片集群中维护唯一性。

  • 标识需要唯一约束但不能作为分片键一部分的字段。

  • 确认现有文档不违反该字段的唯一性约束。

考虑一个存储用户信息的集合records。字段email 不是分片键,但必须是唯一的。 proxy集合包含以下字段:

{ "_id" : ObjectId("..."), "email" : "<string>"}
1

在 proxy集合的 email字段上创建唯一索引:

db.proxy.createIndex( { "email" : 1 }, { unique : true } )
email_1
2

将包含目标字段和生成的唯一ID 的文档插入 proxy集合,然后将完整文档插入 records集合。在一个ACID 事务中运行两个插入操作,以便MongoDB要么应用这两个写入,要么都不应用:

// Start a sessionsession = db.getMongo().startSession( { readPreference: { mode: "primary" } } );proxy = session.getDatabase( db.getName() ).proxy;records = session.getDatabase( db.getName() ).records; var primary_id = ObjectId(); // Start a transactionsession.startTransaction( { readConcern: { level: "local" }, writeConcern: { w: "majority" } } ); // Operations inside the transactiontry { proxy.insertOne( { "_id" : primary_id, "email" : "example@example.net" } ); records.insertOne( { "_id" : primary_id, "email" : "example@example.net", // additional information... } );} catch (error) { // A duplicate email value fails the proxy insert and // cancels the transaction session.abortTransaction(); throw error;}// Commit the transaction using write concern set at transaction startsession.commitTransaction();session.endSession();

如果 email 值已存在于 proxy集合中,则唯一索引会拒绝插入,ACID 事务会中止,因此不会向 records 添加任何文档。