programing

MongoDB 다대다 어소시에이션

copyandpastes 2023. 3. 15. 23:34
반응형

MongoDB 다대다 어소시에이션

MongoDB와의 다대다 관련성은 어떻게 하시겠습니까?

예를 들어 [사용자(Users)]테이블과 [역할(Roles)]테이블이 있다고 하겠습니다사용자에게는 많은 역할이 있으며 역할에는 많은 사용자가 있습니다.SQL 랜드에서는 UserRoles 테이블을 만듭니다.

Users:
    Id
    Name

Roles:
    Id
    Name

UserRoles:
    UserId
    RoleId

MongoDB에서는 같은 종류의 관계가 어떻게 처리됩니까?

질의 요구에 따라 모든 내용을 사용자 문서에 저장할 수 있습니다.

{name:"Joe"
,roles:["Admin","User","Engineer"]
}

모든 엔지니어를 구하려면 다음 명령을 사용합니다.

db.things.find( { roles : "Engineer" } );

별도의 문서에서 역할을 유지 관리하려는 경우, 이름 대신 문서의 _id를 역할 배열에 포함할 수 있습니다.

{name:"Joe"
,roles:["4b5783300334000000000aa9","5783300334000000000aa943","6c6793300334001000000006"]
}

다음과 같은 역할을 설정합니다.

{_id:"6c6793300334001000000006"
,rolename:"Engineer"
}

RDBMS에 대한 다년간의 경험에 따라 모델링을 시도하는 대신 읽기 사용 사례에 맞게 최적화하고 쓰기 사용 사례에 따라 지원되어야 하는 원자적 쓰기 작업을 고려함으로써 MongoDB, Redis 및 기타 NoSQL 데이터스토어를 사용하여 문서 저장소 솔루션을 모델화하는 것이 훨씬 더 쉽다는 것을 알게 되었습니다.

예를 들어, "역할에 있는 사용자" 도메인의 용도는 다음과 같습니다.

  1. 역할 - "Is User In Role"(컨테이너 + 자체 메타데이터)을 지원하기 위해 작성, 읽기, 업데이트, 삭제, 사용자 목록 표시, 사용자 추가, 삭제, 모든 사용자 지우기, 사용자 색인 또는 이와 유사한 작업을 수행합니다.
  2. 사용자 - 생성, 읽기, 업데이트, 삭제(독립 엔티티와 같은 CRUD 작업)

이것은 다음 문서 템플릿으로 모델링할 수 있습니다.

User: { _id: UniqueId, name: string, roles: string[] }
    Indexes: unique: [ name ]
Role: { _id: UniqueId, name: string, users: string[] }
    Indexes: unique: [ name ]

User 엔티티, User의 역할 관련 기능 등 빈번한 사용을 지원합니다.역할은 의도적으로 정규화 해제되어 사용자와 역할에 저장됩니다.중복된 스토리지를 가진 사용자.

텍스트에 쉽게 나타나지는 않지만 문서 저장소를 사용할 때 권장되는 사고 유형입니다.

나는 이것이 업무의 읽기 측면에 대한 격차를 해소하는 데 도움이 되기를 바란다.

쓰기 측면에서 권장되는 것은 원자적 쓰기에 따라 모델링하는 것입니다.예를 들어, 문서 구조가 잠금을 획득하고, 한 문서를 업데이트하고, 다른 문서를 업데이트하고, 잠금을 해제해야 하는 경우 모델이 실패했을 수 있습니다.분산형 잠금장치를 구축할 수 있다고 해서 그 잠금장치를 사용해야 하는 것은 아닙니다.

User in Roles 모델의 경우 잠금에 대한 원자적 쓰기 회피를 확장하는 작업은 역할에 사용자를 추가하거나 역할에 사용자를 제거하는 것입니다.두 경우 모두 작업이 성공하면 단일 사용자 문서와 단일 역할 문서가 모두 업데이트됩니다.장애가 발생했을 경우 청소가 용이합니다.이것이 문서 저장소가 사용되는 작업 단위 패턴이 자주 나타나는 이유 중 하나입니다.

잠금에 대한 원자적 쓰기 회피를 실제로 확장시키는 작업은 역할을 클리어하는 것입니다.그 결과 User.roles 어레이에서 Role.name를 삭제하기 위한 많은 사용자 업데이트가 발생합니다.이 클리어 조작은 일반적으로 권장되지 않지만, 필요에 따라 조작을 주문함으로써 구현할 수 있습니다.

  1. Role.users에서 사용자 이름 목록을 가져옵니다.
  2. 1단계부터 사용자 이름을 반복하고 User.roles에서 역할 이름을 삭제합니다.
  3. Role.users를 클리어합니다.

순서 2에서 발생할 가능성이 가장 높은 문제의 경우 순서 1의 동일한 사용자 이름 세트를 사용하여 복구하거나 계속할 수 있으므로 롤백이 쉽습니다.

방금 이 질문을 받았는데, 오래된 질문이지만 답변에 언급되지 않은 몇 가지 가능성을 추가하는 것이 도움이 될 것 같습니다.또한 최근 몇 년 동안 상황이 다소 진전되었기 때문에 SQL과 NoSQL은 서로 더 가까워지고 있음을 강조할 필요가 있습니다.

논객 중 한 명이 "데이터가 관계형이라면 관계형 사용"이라는 현명한 주의 태도를 제기했습니다.그러나 이 코멘트는 스키마가 항상 애플리케이션보다 우선하는 관계형 세계에서만 의미가 있습니다.

RETALIONAL WORLD: 데이터 구조화> 응용 프로그램 쓰기
NOSQL WORLD: 어플리케이션 설계> 에 따른 데이터 구조화

데이터가 관계형인 경우에도 NoSQL은 옵션입니다.예를 들어 일대다 관계는 전혀 문제가 되지 않으며 MongoDB 문서에서 광범위하게 다루어집니다.

2010년 문제에 대한 2015년 솔루션

이 질문이 게시된 이후 noSQL을 SQL에 접근시키려는 진지한 시도가 있었습니다.캘리포니아 대학(샌디에이고)의 Yannis Papakonstinou가 이끄는 팀은 SQL++의 구현인 FORWARD를 연구해 왔습니다.이 구현은 곧 여기에 게재된 것과 같은 지속적인 문제에 대한 해결책이 될 것입니다.

좀 더 실용적인 차원에서 Couchbase 4.0의 출시로 처음으로 NoSQL에서 네이티브 JOIN을 실행할 수 있게 되었습니다.N1QL을 사용하다이 바로 이은은의의 of of of of of of of of of of의 예입니다.JOIN다음 튜토리얼을 참조하십시오.

SELECT usr.personal_details, orders 
        FROM users_with_orders usr 
            USE KEYS "Elinor_33313792" 
                JOIN orders_with_users orders 
                    ON KEYS ARRAY s.order_id FOR s IN usr.shipped_order_history END

N1QL은 집약, 필터링 등을 포함한 모든 SQL 작업을 지원합니다.

그다지 새로운 하이브리드 솔루션

그래도 MongoDB가 유일한 옵션이라면 데이터 구조보다 어플리케이션이 우선해야 한다는 요점으로 되돌아가고 싶습니다.어떤 답변도 하이브리드 임베딩을 언급하지 않습니다. 하이브리드 임베딩은 대부분의 쿼리된 데이터가 문서/객체에 내장되어 있으며 소수의 경우에 대해 참조가 유지됩니다.

예: 정보(역할명 이외)는 대기할 수 있습니까?사용자가 아직 필요로 하지 않는 것을 요구하지 않음으로써 애플리케이션의 부트스트래핑이 빨라질 수 있습니까?

사용자가 로그인하여 소속된 모든 역할의 모든 옵션을 표시해야 하는 경우일 수 있습니다.그러나 사용자는 "엔지니어"이므로 이 역할의 옵션은 거의 사용되지 않습니다.즉, 어플리케이션은 엔지니어가 옵션을 클릭하는 경우에만 해당 옵션을 표시하면 됩니다.

이는 (1) 사용자가 속한 역할과 (2) 특정 역할에 연결된 이벤트에 대한 정보를 어디서 얻을 수 있는지 시작 시 응용 프로그램에 알려주는 문서를 통해 달성할 수 있습니다.

   {_id: ObjectID(),
    roles: [[“Engineer”, “ObjectId()”],
            [“Administrator”, “ObjectId()”]]
   }

또는 역할 컬렉션의 role.name 필드를 인덱싱하면 개체를 포함할 필요가 없습니다.ID() 중 하나입니다.

또 다른 예: 모든 역할에 대한 정보가 항상 요청됩니까?

사용자가 대시보드에 로그인하여 90%의 시간이 "엔지니어" 역할에 연결된 작업을 수행하는 경우도 있습니다.하이브리드 임베딩은 특정 역할에 대해 전체적으로 수행되고 나머지 역할에 대해서만 참조를 유지할 수 있습니다.

{_id: ObjectID(),
  roles: [{name: “Engineer”, 
           property1: value1,
           property2: value2
          },   
          [“Administrator”, “ObjectId()”]
         ]
}

스키마가 없는 것은 NoSQL만의 특징이 아니라 이 경우 장점이 될 수 있습니다.사용자 개체의 "롤" 속성에 다른 유형의 개체를 중첩하는 것이 완벽하게 유효합니다.

다음의 2개의 어프로치를 사용할 수 있습니다.

첫 번째 접근법

사용자 문서 역할 목록에 참조 링크 추가(배열):

{
  '_id': ObjectId('312xczc324vdfd4353ds4r32')
  user:faizanfareed,
  roles : [
           {'roleName':'admin', # remove this because when we will be updating some roles name we also need to be update in each user document. If not then ignore this.
             roleId: ObjectID('casd324vfdg65765745435v')
          },
            {'roleName':'engineer',
           roleId: ObjectID('casd324vfdvxcv7454rtr35vvvvbre')
           },
          ]
}

또한 (쿼리 요건에 따라) 역할 문서 사용자 목록(어레이)에 사용자 참조 ID를 추가할 수도 있습니다.

{
  roleName:admin,
  users : [{userId: ObjectId('312xczc324vdfd4353ds4r32')}, .......]
}

그러나 역할 문서 크기에 사용자 ID를 추가하는 것은 16MB를 초과하여 전혀 좋지 않습니다.역할 문서 크기가 초과하지 않고 사용자 크기가 제한될 경우 이 방법을 사용할 수 있습니다.필요하지 않은 경우 역할 ID를 사용자 문서에만 추가할 수 있습니다.


종래의 두 번째 어프로치

각 문서에 사용자와 역할의 ID가 모두 포함된 새 집합을 작성합니다.

{
  '_id': ObjectId('mnvctcyu8678hjygtuyoe')
  userId: ObjectId('312xczc324vdfd4353ds4r32')
  roleId: ObjectID('casd324vfdg65765745435v')
            
}

문서 크기는 초과하지 않지만 이 접근 방식에서는 읽기 작업이 쉽지 않습니다.


요건에 근거해 제1 또는 제2의 어프로치를 채용하고 있습니다.

최종 코멘트: 첫 번째 접근방식으로 사용자 문서 배열에 roleId만 추가합니다.사용자보다 큰 역할은 없습니다.사용자 문서 크기는 16MB를 초과하지 않습니다.

종업원과 회사가 엔티티 오브젝트인 경우 다음 스키마를 사용하려고 하는 경우:

employee{
   //put your contract to employee
   contracts:{ item1, item2, item3,...}
}

company{
   //and duplicate it in company
   contracts:{ item1, item2, item3,...}
}

언급URL : https://stackoverflow.com/questions/2336700/mongodb-many-to-many-association

반응형