Các cách để triển khai phiên bản dữ liệu trong MongoDB


298

Bạn có thể chia sẻ suy nghĩ của mình về cách bạn sẽ triển khai phiên bản dữ liệu trong MongoDB không. (Tôi đã hỏi câu hỏi tương tự liên quan đến Cassandra . Nếu bạn có bất kỳ suy nghĩ nào db tốt hơn cho điều đó xin vui lòng chia sẻ)

Giả sử rằng tôi cần phiên bản hồ sơ trong một sổ địa chỉ đơn giản. (Hồ sơ sổ địa chỉ được lưu trữ dưới dạng đối tượng json phẳng). Tôi hy vọng rằng lịch sử:

  • sẽ được sử dụng không thường xuyên
  • sẽ được sử dụng tất cả cùng một lúc để trình bày nó theo kiểu "cỗ máy thời gian"
  • sẽ không có nhiều phiên bản hơn vài trăm đến một bản ghi. lịch sử sẽ không hết hạn

Tôi đang xem xét các phương pháp sau:

  • Tạo một bộ sưu tập đối tượng mới để lưu trữ lịch sử của các bản ghi hoặc thay đổi các bản ghi. Nó sẽ lưu trữ một đối tượng trên mỗi phiên bản có tham chiếu đến mục nhập sổ địa chỉ. Những hồ sơ như vậy sẽ như sau:

    {
     '_id': 'id mới',
     'người dùng': user_id,
     'dấu thời gian': dấu thời gian,
     'address_book_id': 'id của bản ghi sổ địa chỉ' 
     'old_record': {'first_name': 'Jon', 'last_name': 'Doe' ...}
    }
    

    Cách tiếp cận này có thể được sửa đổi để lưu trữ một loạt các phiên bản cho mỗi tài liệu. Nhưng điều này dường như là cách tiếp cận chậm hơn mà không có bất kỳ lợi thế.

  • Lưu trữ các phiên bản dưới dạng đối tượng được tuần tự hóa (JSON) được đính kèm với các mục trong sổ địa chỉ. Tôi không chắc cách gắn các đối tượng đó vào tài liệu MongoDB. Có lẽ như một mảng của chuỗi. ( Được mô hình hóa sau khi Phiên bản tài liệu đơn giản với CouchDB )


1
Tôi muốn biết nếu điều này đã thay đổi kể từ khi câu hỏi đã được trả lời? Tôi không biết nhiều về oplog nhưng điều này vào khoảng thời gian đó, liệu nó có làm nên sự khác biệt?
Randy L

Cách tiếp cận của tôi là nghĩ về tất cả dữ liệu như một chuỗi thời gian.

Câu trả lời:


152

Câu hỏi lớn đầu tiên khi đi sâu vào vấn đề này là "bạn muốn lưu trữ bộ thay đổi như thế nào" ?

  1. Khác biệt?
  2. Bản sao toàn bộ?

Cách tiếp cận cá nhân của tôi sẽ là lưu trữ khác biệt. Bởi vì việc hiển thị các khác biệt này thực sự là một hành động đặc biệt, tôi sẽ đặt các khác biệt trong một bộ sưu tập "lịch sử" khác.

Tôi sẽ sử dụng các bộ sưu tập khác nhau để tiết kiệm không gian bộ nhớ. Bạn thường không muốn có một lịch sử đầy đủ cho một truy vấn đơn giản. Vì vậy, bằng cách giữ lịch sử ra khỏi đối tượng, bạn cũng có thể giữ nó ra khỏi bộ nhớ thường truy cập khi dữ liệu đó được truy vấn.

Để làm cho cuộc sống của tôi dễ dàng, tôi sẽ làm một tài liệu lịch sử có chứa một từ điển các khác biệt được đóng dấu thời gian. Một cái gì đó như thế này:

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

Để làm cho cuộc sống của tôi thực sự dễ dàng, tôi sẽ tạo phần này trong DataObjects (EntityWrapper, bất cứ thứ gì) mà tôi sử dụng để truy cập dữ liệu của mình. Nói chung các đối tượng này có một số dạng lịch sử, do đó bạn có thể dễ dàng ghi đè save()phương thức để thực hiện thay đổi này cùng một lúc.

CẬP NHẬT: 2015-10

Có vẻ như bây giờ có một thông số kỹ thuật để xử lý các khác biệt JSON . Đây có vẻ là một cách mạnh mẽ hơn để lưu trữ các khác biệt / thay đổi.


2
Bạn có lo lắng rằng tài liệu Lịch sử đó (đối tượng thay đổi) sẽ phát triển theo thời gian và các bản cập nhật trở nên không hiệu quả không? Hay MongoDB xử lý tài liệu phát triển dễ dàng?
Piotr Czapla

5
Hãy xem chỉnh sửa. Thêm vào changesthực sự dễ dàng: db.hist.update({_id: ID}, {$set { changes.12345 : CHANGES } }, true)Điều này sẽ thực hiện một upert sẽ chỉ thay đổi dữ liệu cần thiết. Mongo tạo tài liệu với "không gian bộ đệm" để xử lý loại thay đổi này. Nó cũng xem cách các tài liệu trong bộ sưu tập thay đổi và sửa đổi kích thước bộ đệm cho mỗi bộ sưu tập. Vì vậy MongoDB được thiết kế cho chính xác loại thay đổi này (thêm thuộc tính mới / đẩy vào mảng).
Gates VP

2
Tôi đã thực hiện một số thử nghiệm và thực sự việc đặt chỗ không gian hoạt động khá tốt. Tôi đã không thể bắt được sự mất hiệu suất khi các bản ghi được phân bổ lại đến cuối tệp dữ liệu.
Piotr Czapla

4
Bạn có thể sử dụng github.com/mirek/node-rus-diff để tạo khác biệt (tương thích MongoDB) cho lịch sử của bạn.
Mirek Rusin

1
Các JSON patch RFC cung cấp một cách để thể hiện difffs. Nó có triển khai trong một số ngôn ngữ .
Jérôme

31

Có một sơ đồ phiên bản gọi là "Vermongo" giải quyết một số khía cạnh chưa được xử lý trong các câu trả lời khác.

Một trong những vấn đề này là cập nhật đồng thời, một vấn đề khác là xóa tài liệu.

Vermongo lưu trữ các bản sao tài liệu đầy đủ trong một bộ sưu tập bóng. Đối với một số trường hợp sử dụng, điều này có thể gây ra quá nhiều chi phí, nhưng tôi nghĩ nó cũng đơn giản hóa nhiều thứ.

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


5
Làm thế nào để bạn thực sự sử dụng nó?
giờ 49

6
Không có tài liệu về cách dự án này thực sự được sử dụng. Nó có phải là thứ gì đó sống với Mongo không? Nó là một thư viện Java? Có phải nó chỉ là một cách nghĩ về vấn đề? Không có ý tưởng và không có gợi ý được đưa ra.
ftrotter

1
Đây thực sự là một ứng dụng java và mã liên quan nằm ở đây: github.com/thiloplanz/v7files/blob/master/src/main/java/v7db/
tựa

20

Đây là một giải pháp khác sử dụng một tài liệu duy nhất cho phiên bản hiện tại và tất cả các phiên bản cũ:

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

datachứa tất cả các phiên bản. Các datamảng được ra lệnh , phiên bản mới sẽ chỉ nhận được $pushed đến cuối mảng. data.vidlà id phiên bản, là số tăng dần.

Nhận phiên bản mới nhất:

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

Nhận một phiên bản cụ thể bằng cách vid:

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

Chỉ trả về các trường được chỉ định:

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

Chèn phiên bản mới: (và ngăn chèn / cập nhật đồng thời)

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

2vidphiên bản mới nhất hiện tại và 3là phiên bản mới được chèn vào. Bởi vì bạn cần phiên bản mới nhất vid, nên thật dễ dàng để có phiên bản tiếp theo vid: nextVID = oldVID + 1.

Điều $andkiện sẽ đảm bảo, đó 2là mới nhất vid.

Bằng cách này, không cần một chỉ mục duy nhất, nhưng logic ứng dụng phải quan tâm đến việc tăng vidchèn.

Xóa một phiên bản cụ thể:

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

Đó là nó!

(nhớ giới hạn 16 MB cho mỗi giới hạn tài liệu)


Với lưu trữ mmapv1, mỗi khi một phiên bản mới được thêm vào dữ liệu, có khả năng tài liệu sẽ được di chuyển.
raok1997

Vâng đúng vậy. Nhưng nếu bạn chỉ thêm các phiên bản mới mỗi lần, điều này sẽ bị bỏ qua.
Benjamin M


9

Tôi đã làm việc thông qua giải pháp này chứa các phiên bản dữ liệu đã được công bố, dự thảo và lịch sử:

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

Tôi giải thích thêm về mô hình ở đây: http://software.danielwatrous.com/interesenting-revision-data-in-mongodb/

Đối với những người có thể triển khai một cái gì đó như thế này trong Java , đây là một ví dụ:

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

Bao gồm tất cả các mã mà bạn có thể rẽ nhánh, nếu bạn muốn

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


Công cụ tuyệt vời :)
Jonathan


4

Một tùy chọn khác là sử dụng plugin 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

Tôi đã sử dụng gói dưới đây cho dự án sao băng / MongoDB và nó hoạt động tốt, ưu điểm chính là nó lưu trữ lịch sử / sửa đổi trong một mảng trong cùng một tài liệu, do đó không cần thêm ấn phẩm hoặc phần mềm trung gian để truy cập lịch sử thay đổi . Nó có thể hỗ trợ một số lượng hạn chế các phiên bản trước (ví dụ: mười phiên bản mới nhất), nó cũng hỗ trợ kết nối thay đổi (vì vậy tất cả các thay đổi xảy ra trong một khoảng thời gian cụ thể sẽ được bao gồm trong một lần sửa đổi).

nicklozon / sao băng-bộ sưu tập-sửa đổi

Một tùy chọn âm thanh khác là sử dụng Thiên thạch Vermongo ( tại đây )

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.