嵌套对象上的MongoDB唯一索引

问题描述

这是我的MongoDB集合:

{
    "_id": "0","profiles": {
        "A123": {
            "name": "Mike"
        },"B456": {
            "name": "John"
        }
}

我想确保字段“名称”不能具有相同的值。如果有人叫迈克,那么没人可以叫迈克

如果我尝试在“配置文件”中的该集合中创建一个名称已经被使用的新对象,如何创建一个会引发错误的索引?

解决方法

使用您当前的结构,您将无法做到。这样unique index可以将某个嵌套值用作引用作为唯一索引的点,这种方式可以区分文档而不是单个文档。

您可以执行以下两项操作之一:

  1. 更改文档结构。将您的文档更改为类似的内容:
[
  {
    "_id": "0","profile": {
      "name": "Mike","key": "A123"
    }
  },{
    "_id": "1","profile": {
      "name": "John","key": "B456"
    }
  }
]

使用这样的结构,您可以像这样在profile.name上创建唯一索引:

db.collection.createIndex({"profile.name" : 1},{ unique: true } );
  1. 拥有另一个名为名称的集合,并将其用作参考。请注意,如果您经常更新名称,这可能会导致很多开销操作。如果不是这样的话,那将是对您的问题的快速简便的解决方案,因为您只需在插入/删除操作中对其进行更新。
,
//code from output of windows mongo shell client CLI(command line interface)
//create a collection for profiles with objects shown
db.test5.insertMany(
[
 {
    "_id": "0","profiles": {
        "A123": {
            "name": "Mike"
        },"B456": {
            "name": "John"
            }
   }
   }
]);
> db.test5.find().pretty();
{
        "_id" : "0","profiles" : {
                "A123" : {
                        "name" : "Mike"
                },"B456" : {
                        "name" : "John"
                }
        }
}
>
> db.test5.find().pretty();
{
        "_id" : "0","B456" : {
                        "name" : "John"
                }
        }
}
>//create index with the path leading to name,//"*" is used as its not unique within the object path
//check index is created
> db.test5.getIndexes();
[
        {
                "v" : 2,"key" : {
                        "_id" : 1
                },"name" : "_id_","ns" : "test.test5"
        },{
                "v" : 2,"key" : {
                        "profiles.*.name" : 1
                },"name" : "profiles.*.name_1","ns" : "test.test5"
        }
]
//test duplicate document insertion for "Mike" as document exists for "Mike"
> db.test5.insertOne(
...  {
...     "_id": "0",...     "profiles": {
...         "A123": {
...             "name": "Mike"
...         }
...      }
...    }
... );
2020-09-13T13:23:04.908+0530 E  QUERY    [js] WriteError({
        "index" : 0,"code" : 11000,"errmsg" : "E11000 duplicate key error collection: test.test5 index: _id_ dup key: { _id: \"0\" }","op" : {
                "_id" : "0","profiles" : {
                        "A123" : {
                                "name" : "Mike"
                        }
                }
        }
}) :
WriteError({
        "index" : 0,"profiles" : {
                        "A123" : {
                                "name" : "Mike"
                        }
                }
        }
})
WriteError@src/mongo/shell/bulk_api.js:458:48
mergeBatchResults@src/mongo/shell/bulk_api.js:855:49
executeBatch@src/mongo/shell/bulk_api.js:919:13
Bulk/this.execute@src/mongo/shell/bulk_api.js:1163:21
DBCollection.prototype.insertOne@src/mongo/shell/crud_api.js:264:9
@(shell):1:1
//re-check the collection,no duplicates are inserted
> db.test5.find().pretty();
{
        "_id" : "0","B456" : {
                        "name" : "John"
                }
        }
}
>