MongoDB / NoSQL : 문서 변경 기록 유지
데이터베이스 응용 프로그램에서 매우 일반적인 요구 사항은 데이터베이스에서 하나 이상의 특정 엔터티에 대한 변경 사항을 추적하는 것입니다. 이것을 행 버전 관리, 로그 테이블 또는 기록 테이블이라고 들었습니다 (다른 이름이 있다고 확신합니다). RDBMS에서 여러 가지 방법으로 접근 할 수 있습니다. 모든 소스 테이블의 모든 변경 사항을 단일 테이블 (더 많은 로그)에 쓰거나 각 소스 테이블에 대해 별도의 히스토리 테이블을 가질 수 있습니다. 응용 프로그램 코드 또는 데이터베이스 트리거를 통해 로깅을 관리하는 옵션도 있습니다.
NoSQL / 문서 데이터베이스 (특히 MongoDB)에서 동일한 문제에 대한 솔루션이 어떻게 보이는지, 어떻게 균일하게 해결되는지 생각하려고합니다. 문서의 버전 번호를 작성하고 덮어 쓰지 않는 것만 큼 간단합니까? "실제"문서와 "로그 된"문서에 대한 별도의 컬렉션을 만드시겠습니까? 이것이 쿼리 및 성능에 어떤 영향을 미칩니 까?
어쨌든, 이것은 NoSQL 데이터베이스에서 일반적인 시나리오입니까? 그렇다면 일반적인 해결책이 있습니까?
좋은 질문입니다. 나는 이것도 직접 조사하고있었습니다.
변경 될 때마다 새 버전을 만듭니다.
Ruby 용 Mongoid 드라이버 의 버전 관리 모듈 을 발견했습니다. 나는 그것을 직접 사용하지는 않았지만 찾을 수있는 것에서 각 문서에 버전 번호를 추가합니다. 이전 버전은 문서 자체에 포함되어 있습니다. 가장 큰 단점은 변경 될 때마다 전체 문서가 복제 되어 큰 문서를 처리 할 때 많은 중복 컨텐츠가 저장된다는 것입니다. 이 방법은 작은 크기의 문서를 처리하거나 문서를 자주 업데이트하지 않는 경우에 좋습니다.
변경 사항을 새 버전으로 만 저장
또 다른 방법은 변경된 필드 만 새 버전 으로 저장 하는 것 입니다. 그런 다음 내역을 '평평하게'하여 모든 버전의 문서를 재구성 할 수 있습니다. 그러나 모델의 변경 사항을 추적하고 응용 프로그램이 최신 문서를 재구성 할 수있는 방식으로 업데이트 및 삭제를 저장해야하기 때문에 다소 복잡합니다. 플랫 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" }
]
}
]
}
Marking part of the document as deleted in a version is still somewhat awkward though. You could introduce a state
field for parts that can be deleted/restored from your application:
{
author: "xxx",
body: [
{ version: 4, value: "Spam" }
],
state: [
{ version: 4, deleted: false },
{ version: 5, deleted: true }
]
}
With each of these approaches you can store an up-to-date and flattened version in one collection and the history data in a separate collection. This should improve query times if you're only interested in the latest version of a document. But when you need both the latest version and historical data, you'll need to perform two queries, rather than one. So the choice of using a single collection vs. two separate collections should depend on how often your application needs the historical versions.
Most of this answer is just a brain dump of my thoughts, I haven't actually tried any of this yet. Looking back on it, the first option is probably the easiest and best solution, unless the overhead of duplicate data is very significant for your application. The second option is quite complex and probably isn't worth the effort. The third option is basically an optimization of option two and should be easier to implement, but probably isn't worth the implementation effort unless you really can't go with option one.
Looking forward to feedback on this, and other people's solutions to the problem :)
We have partially implemented this on our site and we use the 'Store Revisions in a separate document" (and separate database). We wrote a custom function to return the diffs and we store that. Not so hard and can allow for automated recovery.
Why not a variation on Store changes within the document ?
Instead of storing versions against each key pair, the current key pairs in the document always represents the most recent state and a 'log' of changes is stored within a history array. Only those keys which have changed since creation will have an entry in the log.
{
_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" }
}
]
}
One can have a current NoSQL database and a historical NoSQL database. There will be a an nightly ETL ran everyday. This ETL will record every value with a timestamp, so instead of values it will always be tuples (versioned fields). It will only record a new value if there was a change made on the current value, saving space in the process. For example, this historical NoSQL database json file can look like so:
{
_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" }
]
}
]
}
참고URL : https://stackoverflow.com/questions/3507624/mongodb-nosql-keeping-document-change-history
'IT story' 카테고리의 다른 글
CSS가 음수 패딩을 지원하지 않는 이유는 무엇입니까? (0) | 2020.07.19 |
---|---|
그리드 레이아웃 및 행 / 열 스팬 (0) | 2020.07.19 |
Java에서 메소드 매개 변수를 final로 선언 해야하는 성능상의 이유가 있습니까? (0) | 2020.07.19 |
Java 또는 C #의 예외 관리 모범 사례 (0) | 2020.07.19 |
Git에서 현재 커밋 해시를 같은 커밋의 파일에 쓰는 방법 (0) | 2020.07.19 |