programing

MongoDB/NoSQL: 문서 변경 기록 보관

skycolor 2023. 3. 18. 08:25
반응형

MongoDB/NoSQL: 문서 변경 기록 보관

데이터베이스 어플리케이션에서 매우 일반적인 요건은 데이터베이스 내의 하나 이상의 특정 엔티티에 대한 변경을 추적하는 것입니다.행 버전 관리, 로그 테이블 또는 이력 테이블이라고 불리는 것을 들었습니다(다른 이름이 있을 것입니다).RDBMS 에서는, 다양한 방법으로 액세스 할 수 있습니다.모든 소스 테이블로부터의 모든 변경을 단일 테이블(더 많은 로그)에 쓸 수도 있고, 소스 테이블 마다 개별 이력 테이블을 작성할 수도 있습니다.또한 로그인 응용 프로그램 코드를 관리하거나 데이터베이스 트리거를 통해 관리할 수도 있습니다.

NoSQL/문서 데이터베이스(특히 MongoDB)에서 동일한 문제에 대한 해결책이 어떻게 보일지, 그리고 어떻게 균일한 방법으로 해결되는지 생각해 보려고 합니다.문서의 버전 번호를 만들고 덮어쓰지 않는 것만큼 간단합니까?"실제"와 "실제"를 위한 별도의 컬렉션 생성문서 작성은 어떻게 되나요?이것이 쿼리 및 퍼포먼스에 어떤 영향을 미칩니까?

어쨌든 이것은 NoSQL 데이터베이스에서 일반적인 시나리오입니까?그렇다면 일반적인 솔루션이 있습니까?

좋은 질문입니다. 저도 이 문제에 대해 알아보고 있었습니다.

변경 시마다 새 버전 생성

루비용 Mongoid 드라이버의 Versioning 모듈을 우연히 발견했습니다.제가 직접 사용해 본 적은 없지만, 제가 찾아본 바로는 각 문서에 버전 번호가 추가되어 있습니다.이전 버전은 문서 자체에 포함되어 있습니다.큰 단점은 변경 시마다 문서 전체가 복제되므로 큰 문서를 처리할 때 중복된 내용이 많이 저장된다는 것입니다.작은 크기의 문서를 취급하거나 문서를 자주 업데이트하지 않는 경우에도 이 방법은 적합합니다.

새 버전에만 변경 사항 저장

다른 방법은 변경된 필드만 새 버전에 저장하는 것입니다.그런 다음 이력을 '평탄화'하여 문서의 모든 버전을 재구성할 수 있습니다.다만, 애플리케이션의 최신 문서를 재구성할 수 있는 방법으로 모델의 변경 사항을 추적하고 업데이트 및 삭제를 저장해야 하므로, 이 작업은 다소 복잡합니다.플랫 SQL 테이블이 아닌 구조화된 문서를 다루고 있기 때문에 이 작업은 까다로울 수 있습니다.

문서 내에 변경 내용 저장

각 필드에는 개별 이력이 있을 수도 있습니다.이렇게 하면 문서를 특정 버전으로 재구성하는 것이 훨씬 쉬워집니다.응용 프로그램에서 변경 사항을 명시적으로 추적할 필요는 없지만, 값을 변경할 때 속성의 새 버전을 생성하기만 하면 됩니다.문서의 모양은 다음과 같습니다.

{
  _id: "4c6b9456f61f000000007ba6"
  title: [
    { version: 1, value: "Hello world" },
    { version: 6, value: "Foo" }
  ],
  body: [
    { version: 1, value: "Is this thing on?" },
    { version: 2, value: "What should I write?" },
    { version: 6, value: "This is the new body" }
  ],
  tags: [
    { version: 1, value: [ "test", "trivial" ] },
    { version: 6, value: [ "foo", "test" ] }
  ],
  comments: [
    {
      author: "joe", // Unversioned field
      body: [
        { version: 3, value: "Something cool" }
      ]
    },
    {
      author: "xxx",
      body: [
        { version: 4, value: "Spam" },
        { version: 5, deleted: true }
      ]
    },
    {
      author: "jim",
      body: [
        { version: 7, value: "Not bad" },
        { version: 8, value: "Not bad at all" }
      ]
    }
  ]
}

다만, 문서의 일부를 버전내에서 삭제한 것으로 마크 하는 것은, 아직 다소 곤란합니다.하면 될 것 같아요.state응용 프로그램에서 삭제/삭제 가능한 부품 필드:

{
  author: "xxx",
  body: [
    { version: 4, value: "Spam" }
  ],
  state: [
    { version: 4, deleted: false },
    { version: 5, deleted: true }
  ]
}

이러한 접근 방식 각각을 사용하여 최신 및 플랫 버전을 하나의 컬렉션에 저장하고 기록 데이터를 별도의 컬렉션에 저장할 수 있습니다.이렇게 하면 문서의 최신 버전에만 관심이 있는 경우 질의 시간이 단축됩니다.그러나 최신 버전과 기록 데이터가 모두 필요한 경우 한 가지 쿼리가 아닌 두 가지 쿼리를 수행해야 합니다.따라서 단일 컬렉션을 사용할지 아니면 두 개의 개별 컬렉션을 사용할지를 선택할지는 애플리케이션에 이력 버전이 필요한 빈도에 따라 달라집니다.

이 답변의 대부분은 제 생각의 산물일 뿐입니다.저는 아직 아무것도 해보지 않았습니다.다시 생각해 보면 중복 데이터의 오버헤드가 애플리케이션에 큰 영향을 미치지 않는 한 첫 번째 옵션이 가장 쉽고 최선의 솔루션일 것입니다.두 번째 옵션은 매우 복잡하기 때문에 아마 노력할 가치가 없을 것입니다.세 번째 옵션은 기본적으로 옵션2의 최적화로 구현이 용이해야 하지만 옵션1을 사용할 수 없는 경우가 아니라면 구현할 가치가 없습니다.

이에 대한 피드백과 다른 사람들의 문제 해결 방법을 기대하고 있습니다.

문서 내에서 Store의 변경 사항을 수정하면 어떨까요?

문서의 현재 키 쌍은 각 키 쌍에 대한 버전을 저장하는 대신 항상 최신 상태를 나타내며 변경 내용의 '로그'가 이력 배열에 저장됩니다.작성 후 변경된 키만 로그에 항목이 있습니다.

{
  _id: "4c6b9456f61f000000007ba6"
  title: "Bar",
  body: "Is this thing on?",
  tags: [ "test", "trivial" ],
  comments: [
    { key: 1, author: "joe", body: "Something cool" },
    { key: 2, author: "xxx", body: "Spam", deleted: true },
    { key: 3, author: "jim", body: "Not bad at all" }
  ],
  history: [
    { 
      who: "joe",
      when: 20160101,
      what: { title: "Foo", body: "What should I write?" }
    },
    { 
      who: "jim",
      when: 20160105,
      what: { tags: ["test", "test2"], comments: { key: 3, body: "Not baaad at all" }
    }
  ]
}

델은 이 기능을 사이트에 부분적으로 구현하고 있으며, '개정판을 별도의 문서에 저장'(및 별도의 데이터베이스)을 사용하고 있습니다.우리는 diffs를 반환하는 커스텀 함수를 작성하여 저장합니다.그다지 어렵지 않고 자동 복구가 가능합니다.

현재 NoSQL 데이터베이스와 과거 NoSQL 데이터베이스를 가질 수 있습니다.매일 밤 ETL이 실행됩니다.이 ETL은 모든 값을 타임스탬프와 함께 기록하므로 값이 아닌 항상 튜플(버전된 필드)이 됩니다.현재 값이 변경된 경우에만 새 값이 기록되므로 프로세스 공간이 절약됩니다.예를 들어, 이 기록 NoSQL 데이터베이스 json 파일은 다음과 같습니다.

{
  _id: "4c6b9456f61f000000007ba6"
  title: [
    { date: 20160101, value: "Hello world" },
    { date: 20160202, value: "Foo" }
  ],
  body: [
    { date: 20160101, value: "Is this thing on?" },
    { date: 20160102, value: "What should I write?" },
    { date: 20160202, value: "This is the new body" }
  ],
  tags: [
    { date: 20160101, value: [ "test", "trivial" ] },
    { date: 20160102, value: [ "foo", "test" ] }
  ],
  comments: [
    {
      author: "joe", // Unversioned field
      body: [
        { date: 20160301, value: "Something cool" }
      ]
    },
    {
      author: "xxx",
      body: [
        { date: 20160101, value: "Spam" },
        { date: 20160102, deleted: true }
      ]
    },
    {
      author: "jim",
      body: [
        { date: 20160101, value: "Not bad" },
        { date: 20160102, value: "Not bad at all" }
      ]
    }
  ]
}

Python(Python 3+ 이상) 사용자에게는 pymongo's Collection 객체의 확장 버전인 Historical Collection이 있습니다.

문서의 예:

from historical_collection.historical import HistoricalCollection
from pymongo import MongoClient
class Users(HistoricalCollection):
    PK_FIELDS = ['username', ]  # <<= This is the only requirement

# ...

users = Users(database=db)

users.patch_one({"username": "darth_later", "email": "darthlater@example.com"})
users.patch_one({"username": "darth_later", "email": "darthlater@example.com", "laser_sword_color": "red"})

list(users.revisions({"username": "darth_later"}))

# [{'_id': ObjectId('5d98c3385d8edadaf0bb845b'),
#   'username': 'darth_later',
#   'email': 'darthlater@example.com',
#   '_revision_metadata': None},
#  {'_id': ObjectId('5d98c3385d8edadaf0bb845b'),
#   'username': 'darth_later',
#   'email': 'darthlater@example.com',
#   '_revision_metadata': None,
#   'laser_sword_color': 'red'}]

완전히 공개합니다. 저는 패키지 제작자입니다.:)

언급URL : https://stackoverflow.com/questions/3507624/mongodb-nosql-keeping-document-change-history

반응형