我有一个集合
estates
,在 name
字段上有一个唯一索引,因此创建:
db.estates.createIndex ({ "name": 1 }, { unique: true })
这有效 - 尝试插入重复的名称会导致错误。
我尝试在
buildings
子文档(不同建筑物的数组)上创建每个庄园的唯一索引:
db.estates.createIndex ({ "name": 1, "buildings.name": 1 }, { unique: true })
这不起作用;我的
name: 'Building 1'
文档的 buildings
子文档上可以有许多 name: 'Estate 1'
。
样本文件:
{
_id: ObjectId('6661f5ec5236ce287fa26a17'),
name: 'Estate 1',
code: '12345',
buildings: [
{ name: 'Building 3' },
{
name: 'Building 4',
code: '4444',
function: '',
floor_area: '',
number_of_floors: '',
_id: ObjectId('66673d5ae5d0c8f632280614')
},
{
name: 'All buildings',
_id: ObjectId('66ae5a9fc029cb808ff01784')
},
{
name: 'Building 2',
code: '222222',
function: '',
floor_area: '',
number_of_floors: '',
_id: ObjectId('66afaaee36c6939cbbe20611')
},
{
name: 'Building 1',
code: '',
function: '',
floor_area: '',
number_of_floors: '',
_id: ObjectId('6739f3d0858859fdada218ea')
},
{
name: 'Building 1',
code: '',
function: '',
floor_area: '',
number_of_floors: '',
_id: ObjectId('6739f3e3858859fdada218eb')
}
],
building_systems: [
{
name: 'VS01',
category: 'Heating - radiator',
building: 'Building one',
room: '4320',
floor: '04',
control_cabinet: 'AS01',
year: 2008,
components: [
{ name: 'P1', category: 'Pump - circulation' },
{ name: 'ST21', category: 'Actuator - valve' }
]
},
{
_id: ObjectId('6661f5ec5236ce287fa26a15'),
name: 'VV01',
category: 'Hot water',
building: 'Building one',
room: '4320',
floor: '04',
year: 2008
},
{ name: 'LB01', _id: ObjectId('66675021e5d0c8f632280615') }
],
control_cabinets: [
{
_id: ObjectId('6661f5ec5236ce287fa26a16'),
name: 'AS01',
building: 'Building one',
room: '4320',
floor: '04',
year: 2008,
plc_manufacturer: 'Beckhoff',
ip_address: '198.192.0.28',
port: 183,
protocol: 'ADSL'
},
{ name: 'AS02', _id: ObjectId('66675442e5d0c8f632280618') }
],
我错过了什么?
索引按预期方式工作,但不是您期望的方式。
索引针对每个文档,因此
estates
集合只能包含 1 个包含 name: 'Estate 1'
和 buildings.name: 'Building 1'
的文档。当您插入新文档时,系统会检查另一个具有该组合的文档,而不是带有 name: 'Estate 1'
的文档是否具有包含 buildings.name: 'Building 1'
的另一个数组元素。
所以这些文档不能都存在于同一个集合中:
// estates
{
"_id": ObjectId("65494baa21b99c8cff188a11"),
"name": "Estate 1",
"buildings": [
{ "name": "Building 1" },
],
},
{
"_id": ObjectId("65494baa21b99c8cff188a12"),
"name": "Estate 1",
"buildings": [
{ "name": "Building 1" },
],
}
但是这些文件可以:
// estates
{
"_id": ObjectId("65494baa21b99c8cff188a11"),
"name": "Estate 1",
"buildings": [
{ "name": "Building 1" },
{ "name": "Building 1" },
{ "name": "Building 1" }
],
},
{
"_id": ObjectId("65494baa21b99c8cff188a12"),
"name": "Estate 2",
"buildings": [
{ "name": "Building 2" },
{ "name": "Building 2" },
{ "name": "Building 2" }
],
},
{
"_id": ObjectId("65494baa21b99c8cff188a13"),
"name": "Estate 1",
"buildings": [
{ "name": "Building 2" },
{ "name": "Building 3" },
{ "name": "Building 4" },
{ "name": "Building 4" }
],
}
您可能需要考虑将
buildings
存储在另一个集合中,并将父级 Estate._id
存储为引用。然后你可以在这个新集合上建立索引,例如:
db.buildings.createIndex({ "estateId": 1, "name": 1 }, { unique: true });
当您在新的
buildings
集合中创建新文档时,此新索引将确保仅存在一个具有 name: 'Building 1'
的文档,并且 estateId
是对具有以下值的 estates
文档 _id
值的引用name: 'Estate 1'
。
// estates
{
"_id": ObjectId("65494baa21b99c8cff188a11"),
"name": "Estate 1",
"buildings": [
ObjectId("65494baa21b99c8cff188a14"),
],
},
// buildings
{
"_id": ObjectId("65494baa21b99c8cff188a14"),
"estateId": ObjectId("65494baa21b99c8cff188a11"),
"name": "Building 1"
},
{
"_id": ObjectId("65494baa21b99c8cff188a15"),
"estateId": ObjectId("65494baa21b99c8cff188a11"), // ❌ E11000 duplicate key error
"name": "Building 1" // ❌ E11000 duplicate key error
},
这意味着您的
Estate.buildings
数组将只是 ObjectId
数组而不是子文档。您可以做一个$lookup
来加入他们像这样。