วิธีในการปรับใช้ data versioning ใน MongoDB


298

คุณสามารถแบ่งปันความคิดของคุณได้อย่างไรว่าคุณจะใช้การปรับรุ่นข้อมูลใน MongoDB อย่างไร (ฉันได้ถามคำถามที่คล้ายกันเกี่ยวกับคาสซานดราถ้าคุณมีความคิดใดที่ดีกว่าสำหรับที่กรุณาแบ่งปัน)

สมมติว่าฉันต้องการบันทึกเวอร์ชันในสมุดที่อยู่ธรรมดา (บันทึกสมุดที่อยู่จะถูกจัดเก็บเป็นวัตถุแบบ json แบบแบน) ฉันคาดหวังว่าประวัติศาสตร์:

  • จะถูกใช้ไม่บ่อยนัก
  • จะถูกใช้ทั้งหมดในครั้งเดียวเพื่อนำเสนอในแบบ "ไทม์แมชชีน"
  • จะไม่มีรุ่นมากกว่าสองสามร้อยเป็นระเบียนเดียว ประวัติจะไม่หมดอายุ

ฉันกำลังพิจารณาแนวทางต่อไปนี้:

  • สร้างการรวบรวมวัตถุใหม่เพื่อเก็บประวัติของการบันทึกหรือการเปลี่ยนแปลงกับบันทึก มันจะเก็บวัตถุหนึ่งชิ้นต่อรุ่นโดยมีการอ้างอิงไปยังรายการสมุดที่อยู่ บันทึกดังกล่าวจะมีลักษณะดังนี้:

    {
     '_id': 'รหัสใหม่',
     'ผู้ใช้': user_id
     'timestamp': การประทับเวลา
     'address_book_id': 'id ของบันทึกสมุดรายชื่อ' 
     'old_record': {'first_name': 'Jon', 'last_name': 'Doe' ... }
    }
    

    วิธีการนี้สามารถแก้ไขเพื่อเก็บอาร์เรย์ของเวอร์ชันต่อเอกสาร แต่นี่ดูเหมือนจะช้ากว่าโดยไม่มีข้อได้เปรียบใด ๆ

  • จัดเก็บรุ่นเป็นวัตถุที่เป็นอนุกรม (JSON) ที่แนบมากับรายการสมุดที่อยู่ ฉันไม่แน่ใจว่าจะแนบวัตถุดังกล่าวกับเอกสาร MongoDB ได้อย่างไร อาจเป็นชุดของสตริง ( ถ่ายแบบมาจาก Simple Documenting ด้วย CouchDB )


1
ฉันต้องการทราบว่าสิ่งนี้เปลี่ยนแปลงไปหรือไม่ตั้งแต่คำถามได้รับคำตอบ? ฉันไม่ค่อยรู้เรื่อง oplog มากนัก แต่มันเกี่ยวกับเรื่องนี้ในเวลานั้นมันจะสร้างความแตกต่างได้ไหม?
แรนดี้ L

แนวทางของฉันคือคิดถึงข้อมูลทั้งหมดเป็นอนุกรมเวลา

คำตอบ:


152

คำถามใหญ่แรกเมื่อดำน้ำในนี้คือ"คุณต้องการจัดเก็บการเปลี่ยนแปลง"อย่างไร

  1. diffs?
  2. สำเนาบันทึกทั้งหมด?

วิธีการส่วนตัวของฉันคือการแตกต่าง เนื่องจากการแสดงความแตกต่างเหล่านี้เป็นการกระทำพิเศษจริง ๆ ฉันจะใส่ความแตกต่างในคอลเล็กชัน "ประวัติ" ที่แตกต่างกัน

ฉันจะใช้คอลเล็กชันอื่นเพื่อประหยัดพื้นที่หน่วยความจำ โดยทั่วไปคุณไม่ต้องการประวัติเต็มของการสืบค้นแบบง่าย ดังนั้นการป้องกันไม่ให้ประวัติออกมาจากวัตถุคุณยังสามารถเก็บมันไว้ในหน่วยความจำที่เข้าถึงได้โดยทั่วไปเมื่อมีการสอบถามข้อมูล

เพื่อทำให้ชีวิตของฉันง่ายขึ้นฉันจะทำให้เอกสารประวัติมีพจนานุกรมที่มีการประทับเวลาแตกต่างกัน บางสิ่งเช่นนี้

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

เพื่อให้ชีวิตของฉันง่ายขึ้นฉันจะทำให้ส่วนนี้ของ DataObjects ของฉัน (EntityWrapper อะไรก็ตาม) ที่ฉันใช้เพื่อเข้าถึงข้อมูลของฉัน โดยทั่วไปวัตถุเหล่านี้มีรูปแบบของประวัติบางอย่างเพื่อให้คุณสามารถแทนที่save()วิธีการเปลี่ยนแปลงนี้ได้อย่างง่ายดายในเวลาเดียวกัน

อัปเดต: 2015-10

ดูเหมือนว่าขณะนี้มีข้อมูลจำเพาะสำหรับการจัดการ JSON ต่างกัน ดูเหมือนจะเป็นวิธีที่แข็งแกร่งกว่าในการจัดเก็บส่วนต่าง / การเปลี่ยนแปลง


2
คุณไม่ต้องกังวลว่าเอกสารประวัติดังกล่าว (วัตถุการเปลี่ยนแปลง) จะเพิ่มขึ้นในเวลาและการปรับปรุงไม่มีประสิทธิภาพหรือไม่ หรือ MongoDB จัดการกับเอกสารที่เติบโตได้อย่างง่ายดาย?
Piotr Czapla

5
ลองดูที่การแก้ไข การเพิ่มลงในchangesนั้นง่ายมาก: db.hist.update({_id: ID}, {$set { changes.12345 : CHANGES } }, true)สิ่งนี้จะดำเนินการต่อไปอย่างรวดเร็วซึ่งจะเปลี่ยนแปลงข้อมูลที่ต้องการเท่านั้น Mongo สร้างเอกสารด้วย "พื้นที่บัฟเฟอร์" เพื่อจัดการการเปลี่ยนแปลงประเภทนี้ นอกจากนี้ยังเฝ้าดูว่าเอกสารในคอลเลกชันเปลี่ยนแปลงและปรับเปลี่ยนขนาดบัฟเฟอร์สำหรับแต่ละคอลเลกชันอย่างไร ดังนั้น MongoDB ได้รับการออกแบบสำหรับการเปลี่ยนแปลงประเภทนี้อย่างแน่นอน (เพิ่มคุณสมบัติใหม่ / พุชไปยังอาร์เรย์)
Gates VP

2
ฉันทำการทดสอบแล้วและการจองพื้นที่ใช้งานได้ดี ฉันไม่สามารถจับการสูญเสียประสิทธิภาพเมื่อมีการจัดสรรบันทึกใหม่จนสิ้นสุดไฟล์ข้อมูล
Piotr Czapla

4
คุณสามารถใช้github.com/mirek/node-rus-diffเพื่อสร้างความแตกต่าง (เข้ากันได้กับ MongoDB) สำหรับประวัติของคุณ
Mirek Rusin

1
JSON Patch RFCมีวิธีการแสดง difffs แต่ก็มีการใช้งานในหลายภาษา
Jérôme

31

มีรูปแบบการกำหนดเวอร์ชันที่เรียกว่า "Vermongo" ซึ่งกล่าวถึงบางแง่มุมที่ไม่ได้รับการตอบกลับในการตอบกลับอื่น ๆ

หนึ่งในปัญหาเหล่านี้คือการอัปเดตพร้อมกันและอีกเรื่องหนึ่งคือการลบเอกสาร

Vermongo จัดเก็บสำเนาเอกสารที่สมบูรณ์ในชุดเงา สำหรับบางกรณีการใช้งานอาจทำให้เกิดค่าใช้จ่ายมากเกินไป แต่ฉันคิดว่ามันง่ายขึ้นด้วย

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


5
คุณใช้งานจริงได้อย่างไร?
Hadees

6
ไม่มีเอกสารเกี่ยวกับการใช้งานจริงของโครงการนี้ มันเป็นสิ่งที่อาศัยอยู่กับ Mongo หรือเปล่า? มันเป็นห้องสมุด Java? มันเป็นเพียงวิธีการคิดเกี่ยวกับปัญหาหรือไม่ ไม่มีความคิดและไม่มีคำแนะนำใด ๆ
ftrotter

1
นี่คือแอปพลิเคชัน Java และรหัสที่เกี่ยวข้องอยู่ที่นี่: 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อาร์เรย์สั่งซื้อรุ่นใหม่จะเพียง แต่ได้รับ$pushed ถึงจุดสิ้นสุดของอาร์เรย์ data.vidเป็นรหัสเวอร์ชันซึ่งเป็นหมายเลขที่เพิ่มขึ้น

รับรุ่นล่าสุด:

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เป็นvidเวอร์ชันล่าสุดและ3เป็นเวอร์ชั่นใหม่ที่ถูกแทรก เพราะคุณจะต้องเป็นรุ่นล่าสุดของvidมันเป็นเรื่องง่ายที่จะทำจะได้รับรุ่นถัดไป:vidnextVID = oldVID + 1

$andเงื่อนไขจะให้แน่ใจว่าเป็นล่าสุด2vid

วิธีนี้ไม่จำเป็นต้องมีดัชนีที่ไม่ซ้ำกัน แต่ตรรกะของแอปพลิเคชันต้องดูแลการเพิ่มการvidแทรก

ลบเวอร์ชันเฉพาะ:

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

แค่นั้นแหละ!

(จำ 16MB ต่อเอกสาร จำกัด )


ด้วยที่เก็บ mmapv1 ทุกครั้งที่มีการเพิ่มเวอร์ชันใหม่ลงในข้อมูลมีความเป็นไปได้ที่เอกสารจะถูกย้าย
raok1997

ใช่มันเป็นสิ่งที่ถูก. แต่ถ้าคุณเพิ่งเพิ่มรุ่นใหม่ทุกครั้งในขณะนี้ควรจะละเลย
Benjamin M

12

หากคุณกำลังมองหาโซลูชันที่พร้อมใช้งาน -

Mongoid ได้สร้างเวอร์ชันง่าย ๆ

http://mongoid.org/en/mongoid/docs/extras.html#versioning

mongoid-history เป็นปลั๊กอิน Ruby ที่ให้บริการโซลูชั่นที่ซับซ้อนยิ่งขึ้นด้วยการตรวจสอบเลิกทำและทำซ้ำ

https://github.com/aq1018/mongoid-history


18
สำหรับภาษาการเขียนโปรแกรมทับทิม
ftrotter

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

อีกทางเลือกหนึ่งคือใช้ประวัติพังพอนปลั๊กอิน

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

ฉันได้ใช้แพ็คเกจด้านล่างสำหรับโครงการ meteor / MongoDB และทำงานได้ดีข้อได้เปรียบหลักคือมันเก็บประวัติ / การแก้ไขภายในอาร์เรย์ในเอกสารเดียวกันดังนั้นจึงไม่จำเป็นต้องมีสิ่งพิมพ์หรือมิดเดิลแวร์เพิ่มเติมเพื่อเข้าถึงประวัติการเปลี่ยนแปลง . สามารถรองรับรุ่นก่อนหน้าจำนวน จำกัด (เช่นสิบรุ่นล่าสุด) นอกจากนี้ยังรองรับการเปลี่ยนแปลงการต่อข้อมูล (ดังนั้นการเปลี่ยนแปลงทั้งหมดที่เกิดขึ้นภายในระยะเวลาที่กำหนดจะถูกครอบคลุมโดยการแก้ไขหนึ่งครั้ง)

nicklozon / ดาวตกคอลเลกชันการแก้ไข

ตัวเลือกเสียงอื่นคือใช้ Meteor Vermongo ( ที่นี่ )

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.