sql >> データベース >  >> NoSQL >> MongoDB

JavaMongoDBオブジェクトのバージョン管理

    これが、MongoDBエンティティのバージョン管理を実装することになった方法です。助けてくれたStackOverflowコミュニティに感謝します!

    • 変更ログは、エンティティごとに個別の履歴コレクションに保持されます。
    • 大量のデータの保存を回避するために、履歴コレクションには完全なインスタンスは保存されませんが、最初のバージョンとバージョン間の違いのみが保存されます。 (最初のバージョンを省略して、エンティティのメインコレクションの現在のバージョンから「逆方向」にバージョンを再構築することもできます。)
    • Java Object Diffは、オブジェクトの差分を生成するために使用されます。
    • コレクションを正しく操作できるようにするには、equalsを実装する必要があります サブプロパティではなくデータベースの主キーをテストするように、エンティティのメソッド。 (それ以外の場合、JavaObjectDiffはコレクション要素のプロパティの変更を認識しません。)

    バージョニングに使用するエンティティは次のとおりです(ゲッター/セッターなどが削除されました):

    // This entity is stored once (1:1) per entity that is to be versioned
    // in an own collection
    public class MongoDiffHistoryEntry {
        /* history id */
        private String id;
    
        /* reference to original entity */
        private String objectId;
    
        /* copy of original entity (first version) */
        private Object originalObject;
    
        /* differences collection */
        private List<MongoDiffHistoryChange> differences;
    
        /* delete flag */
        private boolean deleted;
    }
    
    // changeset for a single version
    public class MongoDiffHistoryChange {
        private Date historyDate;
        private List<MongoDiffHistoryChangeItem> items;
    }
    
    // a single property change
    public class MongoDiffHistoryChangeItem {
        /* path to changed property (PropertyPath) */
        private String path;
    
        /* change state (NEW, CHANGED, REMOVED etc.) */
        private Node.State state;
    
        /* original value (empty for NEW) */
        private Object base;
    
        /* new value (empty for REMOVED) */
        private Object modified;
    }
    

    saveChangeHistory操作は次のとおりです。

    private void saveChangeHistory(Object working, Object base) {
        assert working != null && base != null;
        assert working.getClass().equals(base.getClass());
    
        String baseId = ObjectUtil.getPrimaryKeyValue(base).toString();
        String workingId = ObjectUtil.getPrimaryKeyValue(working).toString();
        assert baseId != null && workingId != null && baseId.equals(workingId);
    
        MongoDiffHistoryEntry entry = getObjectHistory(base.getClass(), baseId);
        if (entry == null) {
            //throw new RuntimeException("history not found: " + base.getClass().getName() + "#" + baseId);
            logger.warn("history lost - create new base history record: {}#{}", base.getClass().getName(), baseId);
            saveNewHistory(base);
            saveHistory(working, base);
            return;
        }
    
        final MongoDiffHistoryChange change = new MongoDiffHistoryChange();
        change.setHistoryDate(new Date());
        change.setItems(new ArrayList<MongoDiffHistoryChangeItem>());
    
        ObjectDiffer differ = ObjectDifferFactory.getInstance();
        Node root = differ.compare(working, base);
        root.visit(new MongoDiffHistoryChangeVisitor(change, working, base));
    
        if (entry.getDifferences() == null)
            entry.setDifferences(new ArrayList<MongoDiffHistoryChange>());
        entry.getDifferences().add(change);
    
        mongoTemplate.save(entry, getHistoryCollectionName(working.getClass()));
    }
    

    MongoDBでは次のようになります:

    {
      "_id" : ObjectId("5040a9e73c75ad7e3590e538"),
      "_class" : "MongoDiffHistoryEntry",
      "objectId" : "5034c7a83c75c52dddcbd554",
      "originalObject" : {
          BLABLABLA, including sections collection etc.
      },
      "differences" : [{
          "historyDate" : ISODate("2012-08-31T12:11:19.667Z"),
          "items" : [{
              "path" : "/sections[[email protected]]",
              "state" : "ADDED",
              "modified" : {
                "_class" : "LetterSection",
                "_id" : ObjectId("5034c7a83c75c52dddcbd556"),
                "letterId" : "5034c7a83c75c52dddcbd554",
                "sectionIndex" : 2,
                "stringContent" : "BLABLA",
                "contentMimetype" : "text/plain",
                "sectionConfiguration" : "BLUBB"
              }
            }, {
              "path" : "/sections[[email protected]]",
              "state" : "REMOVED",
              "base" : {
                "_class" : "LetterSection",
                "_id" : ObjectId("5034c7a83c75c52dddcbd556"),
                "letterId" : "5034c7a83c75c52dddcbd554",
                "sectionIndex" : 2,
                "stringContent" : "BLABLABLA",
                "contentMimetype" : "text/plain",
                "sectionConfiguration" : "BLUBB"
              }
            }]
        }, {
          "historyDate" : ISODate("2012-08-31T13:15:32.574Z"),
          "items" : [{
              "path" : "/sections[[email protected]]/stringContent",
              "state" : "CHANGED",
              "base" : "blub5",
              "modified" : "blub6"
            }]
        },
        }],
      "deleted" : false
    }
    

    編集:ここに訪問者コードがあります:

    public class MongoDiffHistoryChangeVisitor implements Visitor {
    
    private MongoDiffHistoryChange change;
    private Object working;
    private Object base;
    
    public MongoDiffHistoryChangeVisitor(MongoDiffHistoryChange change, Object working, Object base) {
        this.change = change;
        this.working = working;
        this.base = base;
    }
    
    public void accept(Node node, Visit visit) {
        if (node.isRootNode() && !node.hasChanges() ||
            node.hasChanges() && node.getChildren().isEmpty()) {
            MongoDiffHistoryChangeItem diffItem = new MongoDiffHistoryChangeItem();
            diffItem.setPath(node.getPropertyPath().toString());
            diffItem.setState(node.getState());
    
            if (node.getState() != State.UNTOUCHED) {
                diffItem.setBase(node.canonicalGet(base));
                diffItem.setModified(node.canonicalGet(working));
            }
    
            if (change.getItems() == null)
                change.setItems(new ArrayList<MongoDiffHistoryChangeItem>());
            change.getItems().add(diffItem);
        }
    }
    
    }
    


    1. Redisキーの命名規則と有効な文字

    2. MongoDBエラー:limit=0で再試行可能な書き込みを使用できません

    3. MongoDBの監査ログ

    4. MongoDBでインデックスを作成する3つの方法