MongoDB에서 데이터 버전 관리를 구현하는 방법


298

MongoDB에서 데이터 버전 관리를 어떻게 구현할 것인지 생각을 공유 할 수 있습니까? (나는 카산드라에 대해 비슷한 질문을했다 . 어떤 db가 더 나은지 생각한다면 공유하십시오)

간단한 주소록에 레코드 버전을 지정해야한다고 가정하십시오. 주소록 레코드는 플랫 json 오브젝트로 저장됩니다. 나는 역사를 기대합니다 :

  • 자주 사용되지 않습니다
  • "타임머신"방식으로 제시하기 위해 한 번에 사용됩니다
  • 단일 레코드에 수백 개 이상의 버전이 없습니다. 역사는 만료되지 않습니다.

다음과 같은 접근법을 고려하고 있습니다.

  • 레코드 히스토리 또는 레코드 변경 사항을 저장할 새 오브젝트 콜렉션을 작성하십시오. 주소록 항목을 참조하여 버전 당 하나의 개체를 저장합니다. 이러한 기록은 다음과 같습니다.

    {
     '_id': '새 ID',
     'user': user_id,
     '타임 스탬프': 타임 스탬프,
     'address_book_id': '주소록 레코드의 ID' 
     'old_record': { 'first_name': 'Jon', 'last_name': 'Doe'...}
    }
    

    이 접근 방식은 문서 당 여러 버전의 버전을 저장하도록 수정할 수 있습니다. 그러나 이것은 이점이없는 느린 접근 방식 인 것 같습니다.

  • 주소록 항목에 첨부 된 버전을 직렬화 된 (JSON) 객체로 저장합니다. 그러한 객체를 MongoDB 문서에 첨부하는 방법을 잘 모르겠습니다. 아마도 문자열 배열 일 것입니다. ( CouchDB를 사용한 간단한 문서 버전 화 후 모델링 )


1
질문에 답변 한 이후에 이것이 변경되었는지 알고 싶습니다. 나는 oplog에 대해 많이 알지 못했지만 당시에 주변에 있었습니까?
랜디 L

내 접근 방식은 모든 데이터를 시계열로 생각하는 것입니다.

답변:


152

이것으로 뛰어들 때 가장 큰 문제는 "변경 세트를 어떻게 저장 하겠습니까? "입니다 .

  1. 차이?
  2. 전체 기록 사본?

내 개인적인 접근 방식은 diff를 저장하는 것입니다. 이 diff의 표시는 실제로 특별한 작업이므로 diff를 다른 "역사"컬렉션에 넣을 것입니다.

다른 컬렉션을 사용하여 메모리 공간을 절약합니다. 일반적으로 간단한 쿼리에 대한 전체 기록을 원하지 않습니다. 따라서 히스토리를 오브젝트에서 제외하면 해당 데이터를 조회 할 때 일반적으로 액세스되는 메모리에서이를 유지할 수 있습니다.

인생을 편하게하기 위해 역사 문서에 타임 스탬프 된 diff의 사전을 포함 시키려고합니다. 이 같은:

{
    _id : "id of address book record",
    changes : { 
                1234567 : { "city" : "Omaha", "state" : "Nebraska" },
                1234568 : { "city" : "Kansas City", "state" : "Missouri" }
               }
}

내 인생을 정말 쉽게하기 위해 데이터에 액세스하는 데 사용하는 DataObjects (EntityWrapper 등) 의이 부분을 만들 것입니다. 일반적으로 이러한 개체에는 몇 가지 형식의 기록이 있으므로이 save()방법을 쉽게 재정 의하여 동시에 변경할 수 있습니다 .

업데이트 : 2015-10

이제 JSON diff를 처리 하기 위한 사양 이있는 것 같습니다 . 이것은 차이점 / 변경 사항을 저장하는보다 강력한 방법 인 것 같습니다.


2
이러한 기록 문서 (변경 사항 개체)가 시간이 지남에 따라 업데이트가 비효율적으로 될까 걱정하지 않습니까? 아니면 MongoDB가 문서를 쉽게 확장 할 수 있습니까?
Piotr Czapla

5
편집 내용을 살펴보십시오. 에 추가하는 changes것은 정말 쉽습니다. db.hist.update({_id: ID}, {$set { changes.12345 : CHANGES } }, true)이렇게하면 필요한 데이터 만 변경하는 upsert가 수행됩니다. Mongo는 이러한 유형의 변경을 처리하기 위해 "버퍼 공간"이있는 문서를 만듭니다. 또한 컬렉션의 문서가 어떻게 변경되고 각 컬렉션의 버퍼 크기를 수정하는 방법도 감시합니다. 따라서 MongoDB는 이러한 유형의 변경을 위해 설계되었습니다 (새 속성 추가 / 배열에 푸시).
Gates VP

2
나는 약간의 테스트를했고 실제로 공간 예약은 꽤 잘 작동합니다. 레코드가 데이터 파일 끝으로 재 할당 될 때 성능 손실을 발견 할 수 없었습니다.
Piotr Czapla

4
github.com/mirek/node-rus-diff 를 사용 하여 히스토리에 대한 (MongoDB 호환) diff를 생성 할 수 있습니다 .
Mirek Rusin

1
JSON 패치 RFC는 difffs을 표현하는 방법을 제공합니다. 그것은이 여러 언어로 구현 .
Jérôme

31

다른 답변에서 다루지 않은 일부 측면을 다루는 "Vermongo"라는 버전 관리 체계가 있습니다.

이러한 문제 중 하나는 동시 업데이트이며 다른 문제는 문서를 삭제하는 것입니다.

Vermongo는 전체 문서 사본을 쉐도우 컬렉션으로 저장합니다. 일부 유스 케이스의 경우 너무 많은 오버 헤드가 발생할 수 있지만 많은 것을 단순화한다고 생각합니다.

https://github.com/thiloplanz/v7files/wiki/Vermongo


5
실제로 어떻게 사용합니까?
hadees

6
이 프로젝트가 실제로 어떻게 사용되는지에 대한 문서는 없습니다. 어떻게 든 몽고와 함께 사는 것입니까? Java 라이브러리입니까? 그것은 단지 문제에 대해 생각하는 방법일까요? 아이디어도없고 힌트도 없습니다.
ftrotter

1
이것은 실제로 자바 응용 프로그램이며, relavant 코드는 여기에 살고 : github.com/thiloplanz/v7files/blob/master/src/main/java/v7db/...
ftrotter

20

현재 버전과 모든 이전 버전에 대해 단일 문서를 사용하는 또 다른 솔루션이 있습니다.

{
    _id: ObjectId("..."),
    data: [
        { vid: 1, content: "foo" },
        { vid: 2, content: "bar" }
    ]
}

data모든 버전을 포함 합니다 . data배열되는 순서 새 버전은 얻을 것이다, $push배열의 끝에 에드. data.vid버전 ID이며 증분 숫자입니다.

최신 버전을 받으십시오.

find(
    { "_id":ObjectId("...") },
    { "data":{ $slice:-1 } }
)

다음을 통해 특정 버전을 얻으십시오 vid.

find(
    { "_id":ObjectId("...") },
    { "data":{ $elemMatch:{ "vid":1 } } }
)

지정된 필드 만 반환 :

find(
    { "_id":ObjectId("...") },
    { "data":{ $elemMatch:{ "vid":1 } }, "data.content":1 }
)

새 버전 삽입 : (및 동시 삽입 / 업데이트 방지)

update(
    {
        "_id":ObjectId("..."),
        $and:[
            { "data.vid":{ $not:{ $gt:2 } } },
            { "data.vid":2 }
        ]
    },
    { $push:{ "data":{ "vid":3, "content":"baz" } } }
)

2는 IS vid현재 가장 최신 버전의은과 3삽입하기 새로운 버전입니다. 최신 버전이 필요하기 때문에 vid다음 버전을 쉽게 얻을 수 있습니다 vid.nextVID = oldVID + 1 .

$and조건은 보장됩니다 2최신입니다vid .

이 방법으로 고유 인덱스가 필요하지 않지만 애플리케이션 로직은 vid삽입시 증가를 처리해야 합니다.

특정 버전을 제거하십시오.

update(
    { "_id":ObjectId("...") },
    { $pull:{ "data":{ "vid":2 } } }
)

그게 다야!

(문서 당 16MB 제한을 기억하십시오)


mmapv1 스토리지를 사용하면 새 버전이 데이터에 추가 될 때마다 문서가 이동 될 수 있습니다.
raok1997

네 맞습니다. 그러나 가끔씩 새 버전을 추가하면 무시할 수 있습니다.
Benjamin M


9

게시 된 초안 및 이전 버전의 데이터를 수용하는이 솔루션을 통해 작업했습니다.

{
  published: {},
  draft: {},
  history: {
    "1" : {
      metadata: <value>,
      document: {}
    },
    ...
  }
}

모델을 더 자세히 설명합니다. http://software.danielwatrous.com/representing-revision-data-in-mongodb/

Java 에서 이와 같은 것을 구현할 수있는 사람들을 위한 예제는 다음과 같습니다.

http://software.danielwatrous.com/using-java-to-work-with-versioned-data/

원하는 경우 포크 할 수있는 모든 코드 포함

https://github.com/dwatrous/mongodb-revision-objects


멋진 것들 :)
Jonathan


4

또 다른 옵션은 mongoose-history 플러그인 을 사용하는 것 입니다.

let mongoose = require('mongoose');
let mongooseHistory = require('mongoose-history');
let Schema = mongoose.Schema;

let MySchema = Post = new Schema({
    title: String,
    status: Boolean
});

MySchema.plugin(mongooseHistory);
// The plugin will automatically create a new collection with the schema name + "_history".
// In this case, collection with name "my_schema_history" will be created.

1

유성 / MongoDB 프로젝트에 아래 패키지를 사용했으며 잘 작동합니다. 주된 이점은 동일한 문서의 배열 내에서 기록 / 수정본을 저장하므로 추가 게시 또는 미들웨어가 변경 기록에 액세스 할 필요가 없다는 것입니다 . 제한된 수의 이전 버전 (예 : 마지막 10 개 버전)을 지원할 수 있으며 변경 연결도 지원합니다 (따라서 특정 기간 내에 발생한 모든 변경 사항은 하나의 개정으로 처리됨).

nicklozon / meteor-collection-revisions

또 다른 사운드 옵션은 Meteor Vermongo를 사용하는 것입니다 ( here )

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.