如何为嵌套在数组中的文档中的字段设置唯一约束?
Posted
技术标签:
【中文标题】如何为嵌套在数组中的文档中的字段设置唯一约束?【英文标题】:How to set unique constraint for field in document nested in array? 【发布时间】:2020-08-22 14:35:02 【问题描述】:我在 MongoDB 中有一组文档,如下所示:
"_id": 1, "array": ["id": 1, "content": "...", "id": 2, "content": "..."]
"_id": 2, "array": ["id": 1, "content": "...", "id": 2, "content": "...", "a_id": 3, "content": "..."]
我想确保每个文档中没有重复的array.id
。所以提供的例子是可以的,但followign不是:
"_id": 1, "array": ["id": 1, "content": "...", "id": 1, "content": "..."]
我的问题是如何做到这一点(最好在PyMongo
中)。
编辑
我尝试的是以下代码,我认为它会在 (_id, array.id)
上创建密钥,但如果你运行它,这不会发生:
from pymongo import MongoClient, ASCENDING
client = MongoClient(host="localhost", port=27017)
database = client["test_db"]
collection = database["test_collection"]
collection.drop()
collection.create_index(keys=[("_id", ASCENDING),
("array.id", ASCENDING)],
unique=True,
name="new_key")
document = "array": ["id": 1, "id": 2]
collection.insert_one(document)
collection.find_one_and_update("_id": document["_id"],
"$push": "array": "id": 1)
updated_document = collection.find_one("_id": document["_id"])
print(updated_document)
哪个输出(注意array
中有两个带有id = 1
的对象)。我希望得到一个例外。
'_id': ObjectId('5eb51270d6d70fbba739e3b2'), 'array': ['id': 1, 'id': 2, 'id': 1]
【问题讨论】:
请查看此类似问题并回答Eliminate duplicates in MongoDB with a specific sort @prasad_ 在您提到的帖子中,它仅描述了如何确保您在执行查询时没有重复项,但我希望数据库检查是否有重复项,例如插入一个新的价值。基本上我想要实现的是在(_id, id)
上设置一个“索引”
插入(推入)数组是一种更新操作。确保更新的查询条件检查 id
不存在于子文档数组中。您还可以在数组字段上设置索引 - 这些被称为 Multikey Indexes。请参阅链接中的子主题:唯一多键索引
@prasad_ 我认为多键索引是我正在寻找的。我试过了,但没有运气。所以从文档中我假设我应该将索引设置为db.coll.createIndex( "array.id": 1 )
对吗?我试过了,它不起作用。
请解释一下您所说的“我试过了,但它不起作用。”.
【参考方案1】:
因此,如果我理解正确,则无法设置索引(或 某些条件)将强制文档内的唯一性, 正确的? (除了在创建文档时明确检查或 插入时。)
是的。关于在嵌入文档的数组字段上使用唯一索引,请参见以下两种场景。
Unique Multikey Index(数组内嵌入文档字段的索引):
对于唯一索引,唯一约束适用于不同的 集合中的文档而不是单个文档中的文档。
因为唯一性约束适用于单独的文档,对于一个 唯一的多键索引,文档可能有数组元素,结果 重复索引键值,只要该索引键值 文档不要与其他文档重复。
第一个场景:
db.arrays.createIndex( _id: 1, "array.id": 1, unique: true )
db.arrays.insertOne( "_id": 1, "array": [ "id": 1, "content": "11", "id": 2, "content": "22" ] )
db.arrays.insertOne( "_id": 2, "array": [ "id": 1, "content": "1100", "id": 5, "content": "55" ] )
db.arrays.insertOne( "_id": 3, "array": [ "id": 3, "content": "33", "id": 3, "content": "3300" ] )
所有三个文档都被插入,没有任何错误。
根据上面唯一多键索引的注释,_id : 3
的文档在数组中有两个嵌入的文档,具有相同的"array.id"
value:@987654325 @。
此外,对复合索引 _id: 1, "array.id": 1
的两个键强制执行唯一性,并且文档中也存在重复的 "array.id"
值(_id
值 1
和 2
)。
第二种情况:
db.arrays2.createIndex( "array.id": 1 , unique: true )
db.arrays2.insertOne( "_id": 3, "array": [ "id": 3, "content": "33" , "id": 3, "content": "330" ] )
db.arrays2.insertOne( "_id": 4, "array": [ "id": 3, "content": "331" , "id": 30, "content": "3300" ] )
第一个带有_id : 3
的文档被成功插入。第二个有错误:"errmsg" : "E11000 duplicate key error collection: test.arrays2 index: array.id_1 dup key: array.id: 3.0 "
。此行为与注释 Unique Multikey Index 中的预期一致。
【讨论】:
如果我们这样做,那么它在数据库级别变得独一无二,我想在文档级别进行,有两个数组字段【参考方案2】:您可以在更新时进行此检查
const doc = await Model.findOneAndUpdate(
_id, 'array.id': $ne: newID ,
$push:
array: newID
,
new: true
);
【讨论】:
以上是关于如何为嵌套在数组中的文档中的字段设置唯一约束?的主要内容,如果未能解决你的问题,请参考以下文章
如何为 postgresql 中的唯一(不包括顺序)JSONB 列创建约束
如何为数组中的每个创建一个具有唯一图像和选择器的自定义 UIButton?