发往/来自Mongo的版本化对象/ JSON映射?

IAm*_*aja 5 java serialization json mongodb gson

所以我有一个需要存储某些配置信息的应用程序,因此我计划将配置存储为Mongo中的简单JSON文档:

appConfig: {
    fizz: true,
    buzz: 34
}
Run Code Online (Sandbox Code Playgroud)

这可能映射到Java POJO /实体,如:

public class AppConfig {
    private boolean fizz;
    private int buzz;
}
Run Code Online (Sandbox Code Playgroud)

通常,对于关系数据库,我使用Hibernate/JPA进行从表数据到/从Java实体的O/R映射.我相信最接近表/ Hibernate的JSON/Mongo伴侣是Morphia/GSON组合:使用Morphia驱动从我的Java应用程序到Mongo的连接,然后使用GSON将OSON映射到Java POJO /实体的JSON.

这里的问题是,随着时间的推移,我的appConfig文档结构将发生变化.它可能很简单:

appConfig: {
    fizz: true,
    buzz: 34
    foo: "Hello!"
}
Run Code Online (Sandbox Code Playgroud)

然后,这将要求POJO /实体成为:

public class AppConfig {
    private boolean fizz;
    private int buzz;
    private String foo;
}
Run Code Online (Sandbox Code Playgroud)

但问题是我可能已经存储了数万个已存储在Mongo中的JSON文档,这些文档没有foo属性.在这种特定情况下,显而易见的解决方案是在属性上设置默认值,如:

public class AppConfig {
    private boolean fizz;
    private int buzz;
    private String foo = "Hello!"
}
Run Code Online (Sandbox Code Playgroud)

然而实际上,最终AppConfig文档/模式/结构可能会发生很大变化,以至于它的形状或形式与其原始设计完全不同.但是踢球者是:我需要向后兼容,并且最好能够更新/转换文档以匹配适当的新模式/结构.

我的问题:这个"版本化文档"问题通常是如何解决的?

Sea*_*lly 5

我通常通过向集合中的每个文档添加版本字段来解决此问题.

您可能在AppConfig集合中有多个文档:

{
    _id: 1,
    fizz: true,
    buzz: 34
}

{
    _id: 2,
    version: 1,
    fizz: false,
    buzz: 36,
    foo: "Hello!"
}

{
    _id: 3,
    version: 1,
    fizz: true,
    buzz: 42,
    foo: "Goodbye"
}
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,版本1中有两个文档,而版本为零的一个旧文档(在此模式中,我通常将缺失或null版本字段解释为版本0,因为我只会在版本化时添加此文档通过生产中的文件).

这种模式的两个原则:

  1. 文档在实际修改时始终保存在最新版本中.
  2. 读取文档时,如果文档不是最新版本,则会透明地升级到最新版本.

您可以通过检查版本字段并在版本不够新时执行迁移来执行此操作:

DBObject update(DBObject document) {
    if (document.getInt("version", 0) < 1) {
        document.put("foo", "Hello!"); //add default value for foo
        document.put("version", 1);
    }
    return document;
}
Run Code Online (Sandbox Code Playgroud)

此迁移可以相当轻松地添加具有默认值的字段,重命名字段和删除字段.由于它位于应用程序代码中,因此您可以根据需要进行更复杂的计算.

迁移文档后,您可以通过任何您喜欢的ODM解决方案将其转换为Java对象.此解决方案不再需要担心版本控制,因为它处理的文档都是最新的!

使用Morphia,可以使用@PreLoad注释完成.

两个警告:

  1. 有时您可能希望立即将升级后的文档保存回数据库.最常见的原因是迁移成本高昂,迁移不确定或与其他数据库集成,或者您急于升级旧版本.

  2. 添加或重命名在查询中用作条件的字段有点棘手.实际上,您可能需要执行多个查询,并统一结果.

在我看来,这种模式突出了MongoDB的一大优势:由于文档是在应用程序中进行版本化的,因此您可以在应用程序中无缝迁移数据表示,而无需像SQL数据库那样需要任何离线"迁移阶段".


小智 1

我想下面的线程会对您有所帮助,尽管它与数据库中的文档版本无关,并且它是使用 spring-data-mongodb 完成的,

如何向现有的 spring-data-mongodb 文档集合添加最终字段?

因此,您可以使用 Converter 实现根据文档中属性的存在情况为 POJO 分配值。