如何在 spring 数据中使用 mongodb 的动态模式?

How to use dynamic schema in spring data with mongodb?

Mongodb是一个no-schema文档数据库,但是在spring数据中,需要定义实体class和存储库class,如下:

实体class:

@Document(collection = "users")
public class User implements UserDetails {
    @Id private String userId;
    @NotNull @Indexed(unique = true) private String username;
    @NotNull private String password;
    @NotNull private String name;
    @NotNull private String email;
}

存储库class:

public interface UserRepository extends MongoRepository<User, String> {
    User findByUsername(String username);
}

是否可以在 spring 数据 mongodb 中使用 map 而不是 class 以便服务器可以接受任何动态 JSON 数据然后将其存储在 BSON 中而无需任何pre-class定义?

首先,一些关于无模式数据的有见地的链接:

其次...有人可能想知道 Spring 或 Java 是否是您问题的正确解决方案 - 为什么不是更动态的工具,例如 Ruby,Python 还是 Mongoshell?

话虽如此,让我们关注技术问题。

如果您的目标只是存储随机数据,您基本上可以定义自己的控制器并直接使用 MongoDB Java 驱动程序。

如果您真的坚持没有为您的域对象预定义架构 class,请使用此:

@Document(collection = "users")
public class User implements UserDetails {
    @Id
    private String id;
    private Map<String, Object> schemalessData;

    // getters/setters omitted
}

基本上它为您提供了一个容器,您可以在其中放置任何您想要的东西,但要注意 serialization/deserialization 问题(如果您的嵌套文档中有 ObjectId 和 DBRef,这可能会变得棘手)。此外,如果您的数据层次结构变得过于复杂,更新数据可能会变得令人讨厌。

不过,在某些时候,您会意识到您的数据确实有一个可以精确定位并放入定义明确的 POJO 中的模式。

更新

延迟更新,因为人们在 2020 年仍然碰巧阅读此 post:Jackson 注释 JsonAnyGetter and JsonAnySetter 让您隐藏无模式数据容器的根,以便您的未知字段可以作为有效载荷中的顶级字段。它们仍将嵌套存储在您的 MongoDB 文档中,但在通过 Spring.

请求资源时将显示为顶级字段
@Document(collection = "users")
public class User implements UserDetails {
    @Id
    private String id;

    // add all other expected fields (getters/setters omitted)
    private String foo;
    private String bar;

    // a container for all unexpected fields
    private Map<String, Object> schemalessData;

    @JsonAnySetter
    public void add(String key, Object value) {
        if (null == schemalessData) {
            schemalessData = new HashMap<>();
        }
        schemalessData.put(key, value);
    }

    @JsonAnyGetter
    public Map<String, Object> get() {
        return schemalessData;
    }

    // getters/setters omitted
}