【问题标题】:How can I implement MongoDB Codecs for composite classes?如何为复合类实现 MongoDB 编解码器?
【发布时间】:2019-08-21 13:26:18
【问题描述】:

我正在使用 MongoDB 及其反应流 Java 驱动程序(在 Spring 引导项目中)为现有的数据库访问模块。一些对象以复合方式存储在 DB 中,仅存储参考 ID,然后在从 DB 获取时组装对象(参见示例代码)。我正在使用编解码器来创建 Java 对象,但我不确定如何以复合方式制作东西。

以前使用同步驱动程序的解决方案只是逐字段解析从 MongoDB 返回的文档,并在需要进行数据库查找以进行组装时调用适当的服务。由于该解决方案很快变得完全无法管理,因此我决定使用 MongoDB 编解码器将文档直接解析为 Java 对象。但是,我不确定如何使用编解码器做同样的事情,因为它们似乎不允许我连接到数据库以在创建对象时获取适当的数据,并且在创建后对这些对象进行额外的获取和手动设置似乎效率低下而不是真正正确的方法。

MongoDB 规则集合示例:

{
    "_id": {
        "$oid": "5afa865b613640f83206e23e"
    },
    "id": "R2",
    "typeId": "RT1",
    "name": "example rule",
}

RuleType 集合示例:

{
    "_id": {
        "$oid": "5afa865c613640f83206e260"
    },
    "id": "RT1",
    "name": "Example rule type",
}

Rule.java

public Class Rule {
    private id;
    private name;
    private RuleType ruleType;

    // Constructors, setters, getters, etc.
}

RuleType.java

public Class Rule {
    private id;
    private name;

    // Constructors, setters, getters, etc.
}

RuleDbService.java

public class RuleDbService {
    private final MongoCollection<Rule> ruleCollection;
    private final ObservableSubscriber<Rule> subscriber = new ObservableSubscriber<>();

    public RuleDbService(final MongoDbAdapter mongoDbAdapter) {
        this.ruleCollection = mongoDbAdapter.getCollection("rules", Rule.class);
    }

    public Optional<Rule> findFirst() {
        this.ruleCollection.find().first().subscribe(this.subscriber);
        return Optional.of(this.subscriber.get())
    }

RulesCodec.java

public class RulesCodec implements Codec<Rule> {

    private final Codec<Document> documentCodec;

    public RulesCodec() {
        this.documentCodec = new DocumentCodec();
    }

    public RulesCodec(final Codec<Document> codec) {
        this.documentCodec = codec;
    }


    @Override
    public Rule decode(final BsonReader reader, final DecoderContext decoderContext) {
        final Document document = this.documentCodec.decode(reader, decoderContext);

        final Rule rule = new Rule();
        rule.setId(document.getString("id"));
        // rule.setType() <- How to do this? Can I call to some findById(id) function in RuleTypeDbService from here?
        rule.setName(document.getString("name"));

        return rule;
    }

    @Override
    public void encode(final BsonWriter writer, final Rule value, final EncoderContext encoderContext) {
        final Document document = new Document();

        final String ruleId = value.getId();
        final String name = value.getName();
        final String typeId = (value.getType() != null) ? value.getType().getId() : null;

        if (ruleId != null) {
            document.put("id", ruleId);
        }

        if (name != null) {
            document.put("name", name);
        }

        if (typeId != null) {
            document.put("typeId", typeId);
        }

        this.documentCodec.encode(writer, document, encoderContext);

    }

    @Override
    public Class<Rule> getEncoderClass() {
        return Rule.class;
    }
}

我希望 RuleDbService 能够通过在数据库中查找来组装包括 ruleType 的规则,而不是用空字段返回它,并且我必须在编解码器解析后手动进行外部查找和类型设置或其他一些解决方法。最好的方法是什么?

注意:很遗憾,我无法以任何方式修改数据库或模型结构,因此我无法使用任何 ORM 框架(如 Morphia)需要 MongoDb 中的唯一 id 字段在 Java 模型中表示,因此我必须对文档进行解码手动。

【问题讨论】:

    标签: java mongodb codec reactive-streams


    【解决方案1】:

    您可能会考虑使用带有$lookup 的聚合。 https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/

    【讨论】:

    • 谢谢,这正是我需要的!
    猜你喜欢
    • 2016-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-30
    • 2021-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多