java - NoSQL 无模式数据和静态类型语言

标签 java mongodb nosql

NoSQL 数据存储(如 MongoDB)的主要优势之一是它们是无模式的。对于动态类型语言,这似乎很自然。您可以接收一些任意的 JSON 输入,在已知字段上执行业务逻辑,并在无需首先定义对象的情况下保留整个内容。

如果您选择的语言仅限于静态类型,比如 Java,该怎么办?我怎样才能达到相同水平的灵 active ?

典型的数据流如下:

  1. JSON 输入
  2. 序列化为 Java 对象以执行业务逻辑
  3. 反序列化为 BSON 以在 Mongo 中持久化

因为您想使用 POJO 而不是 JSON 字符串来执行业务逻辑,所以序列化到对象的步骤是必要的。但是,在将输入序列化为对象之前,我必须先定义它。如果输入包含对象中未定义的其他字段怎么办?虽然它们可能不会在业务逻辑中使用,但我可能仍然希望能够持久化它们。我似乎有将未定义字段放入 map 的实现,但我不确定这是否是最好的方法。一方面,未定义的字段也可能是复杂的对象。

最佳答案

无架构数据并不一定意味着无结构数据;这些字段通常是预先知道的,并且可以在其上应用一些类型安全的模式以避免 Magic Container anti-pattern但情况并非总是如此。有时 key 是由用户输入的,无法提前知道。

我用过 Role Object Pattern多次使动态结构连贯。我认为它非常适合这两种情况。

角色对象模式定义了一种访问对象的不同 View 的方法。典型的例子是一个用户可以承担多个角色,例如客户、供应商和卖家。这些 View 中的每一个都有它可以执行的不同操作,并且可以从任何其他 View 访问。公共(public)字段通常在界面级别可用(特别是 userId() ,或者在您的情况下为 toJson() )。

这是使用模式的示例:

public void displayPage(User user) {
    display(user.getName());

    if (user.hasView(Customer.class))
       displayShoppingCart(user.getView(Customer.class);

    if (user.hasView(Seller.class))
       displayProducts(user.getView(Seller.class));
}

对于具有已知结构的数据,您可以使用多个 View 将不同的键集放入内聚单元中。这些不同的 View 可以读取构建上的json数据。

对于具有动态结构的数据,权威的 RawDataView 可以拥有动态形式的数据(即 Magic Container 类似于 HashMap<String, Object> )。这可用于查询动态数据。同时,可以延迟创建类型安全的包装器,并可以委托(delegate)给 RawDataView 以帮助提高程序的可读性/可维护性:

 public class Customer implements User {
     private final RawDataView data;
     public CustomerView(UserView source) {
         this.data = source.getView(RawDataView.class);
     }

     // All User views must specify this
     @Override
     public long id() {
         return data.getId();
     }

     @Override
     public <T extends UserView> T getView(Class<T> view) {
         // construct or look up view
     }

     @Override
     public Json toJson() {
         return data.toJson();
     }


     //
     // Specific to Customer
     //
     public List<Item> shoppingCart() {
         List<Item> items = (List<Item>) data.getValue("items", List.class); 
     }

     // etc....
 }

这两种方法我都取得了成功。以下是我在此过程中发现的一些额外提示:

  • 尽可能对您的数据采用静态结构。这使得事情更容易维护。在遗留系统上工作时,我不得不打破这条规则并使用 RawDataView 方法。如上所述,您可能还必须使用动态输入的用户数据来打破它。在这种情况下,使用非动态字段名称的约定,例如前导下划线 ( _userId )
  • equals() hashcode() 实现使得 user.getView(A.class).equals(user.getView(B.class))对于同一用户始终为真。
  • 有一个 UserCore 类来完成所有繁重的公共(public)代码,例如创建 View ;执行常见操作(如 toJson() )返回常见字段(如 userId() );并实现 equals()hashcode() .将所有 View 委托(delegate)给这个核心对象
  • 有一个 AbstractUserView 委托(delegate)给 UserCore 并实现 equals() 和 hashcode()
  • 使用类型安全的异构容器(如 ClassToInstanceMap )构建/缓存 View 。
  • 允许查询 View 的存在。这可以通过 hasView() 来完成。方法或让 getView 返回 Optional<T>

关于java - NoSQL 无模式数据和静态类型语言,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8005309/

相关文章:

java - 如何将字符串分配给带有错误消息 "Non Static method reference Static Context"的数组列表?

node.js - Mongoose 对象中的虚拟未定义?

c# - DocumentDB 中主键的最佳实践

caching - 使用 nosql 数据存储时是否需要缓存层?

database - 用golang动态查询mongodb

java - 如何从静态 main() 方法调用内部类的方法

java - 二进制到字符串的麻烦

java - 使用 Java DSL 从文件轮询 - 添加 Files.inboundAdapter 时出现编译错误

javascript - 如何使用 javascript 将二进制文件插入 mongodb?

node.js - Mongoose 查询子文档属性