Mongo db 子文档唯一索引问题

问题描述 投票:0回答:1

我有一个集合

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') }
],

我错过了什么?

mongodb indexing subdocument
1个回答
1
投票

索引按预期方式工作,但不是您期望的方式。

索引针对每个文档,因此

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
来加入他们像这样

© www.soinside.com 2019 - 2024. All rights reserved.