MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Кодек MongoDB BSON не се използва при кодиране на обект

След няколко дни проучване намерих решение.

DutyBlockCodec зависи от LocalDateCodec (който създадох), за да кодирам/декодирам. Тази зависимост не е удовлетворена само чрез добавяне на двата кодека в един и същ регистър на кодеци. Решението е да предадете CodecRegistry обект, съдържащ кодеците, които DutyBlockCodec зависи от (например CodecRegistry съдържащ в себе си LocalDateCodec ) към DutyBlockCodec 's конструктор, който се съхранява като член променлива. За да използвате LocalDateCodec за кодиране използвам EncoderContext.encodeWithChildContext() метод, предавайки кодека, записващото устройство и елемента за кодиране. Освен това пиша отделни полета, вместо да пиша Document като String (както в моя оригинален код). Така DutyBlock кодек изглежда така:

public class DutyBlockCodec implements Codec<DutyBlock> {
    private final CodecRegistry codecRegistry;

    public DutyBlockCodec(final CodecRegistry codecRegistry) {
        this.codecRegistry = codecRegistry;
    }

    @Override
    public void encode(BsonWriter writer, DutyBlock t, EncoderContext ec) {
        writer.writeStartDocument();
            Codec dateCodec = codecRegistry.get(LocalDate.class);
            writer.writeName("startDate");
            ec.encodeWithChildContext(dateCodec, writer, t.getStartDate());
            writer.writeName("endDate");
            ec.encodeWithChildContext(dateCodec, writer, t.getEndDate());
            writer.writeName("blockLength");
            writer.writeInt32(t.getBlockLength());
            writer.writeName("pointValue");
            writer.writeDouble(t.getPointValue());

            //Writing ArrayList of RAs
            writer.writeName("assigned");
            writer.writeStartArray();
                for (Ra ra : t.getRasOnDuty()) {
                    Codec raCodec = codecRegistry.get(Ra.class);
                    ec.encodeWithChildContext(raCodec, writer, ra);
                }
            writer.writeEndArray();
        writer.writeEndDocument();
    }

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

    @Override
    public DutyBlock decode(BsonReader reader, DecoderContext dc) {
        reader.readStartDocument();
            Codec<LocalDate> dateCodec = codecRegistry.get(LocalDate.class);
            reader.readName();
            LocalDate startDate = dateCodec.decode(reader, dc);
            reader.readName();
            LocalDate endDate = dateCodec.decode(reader, dc);
            reader.readName();
            int blockLength = reader.readInt32();
            reader.readName();
            double pointValue = reader.readDouble();

            //Reading ArrayList of RAs
            reader.readName();
            Codec<Ra> raCodec = codecRegistry.get(Ra.class);
            ArrayList<Ra> rasOnDuty = new ArrayList<>();
            reader.readStartArray();
                while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
                    rasOnDuty.add(raCodec.decode(reader, dc));
                }
            reader.readEndArray();
        reader.readEndDocument();

        return new DutyBlock(startDate, endDate, blockLength, pointValue, rasOnDuty);
    }

}

DutyBlockCodec зависи от друг кодек и затова изисква CodecRegistry да бъде предадено в неговия конструктор. Въпреки че вярвам, че е възможно да се създаде CodecRegistry с LocalDateCodec , след това предайте това като аргумент на DutyBlockCodec 's конструктор, след което създайте друг CodecRegistry съдържащ и двата LocalDateCodec и DutyBlockCodec , това е доста объркващо и MongoDB предоставя функционалност, CodecProvider за улесняване на този процес.

Използване на CodecProvider интерфейс, написах DutyBlockCodecProvider

public class DutyBlockCodecProvider implements CodecProvider {
    @Override
    public <T> Codec<T> get(Class<T> type, CodecRegistry cr) {
        if (type == DutyBlock.class) {
            return (Codec<T>) new DutyBlockCodec(cr);
        }
        return null;
    }
}

Добавих тези CodecProviders към клиента MongoDB с помощта на CodecRegistries.fromProviders() метод.

CodecRegistry codecRegistry = CodecRegistries.fromRegistries(
            CodecRegistries.fromCodecs(new LocalDateCodec()),
            CodecRegistries.fromProviders(
                    new RaCodecProvider(),
                    new DutyBlockCodecProvider(),
                    new ScheduledDutyCodecProvider()),
            MongoClient.getDefaultCodecRegistry());  
    MongoClientOptions options = MongoClientOptions.builder()
            .codecRegistry(codecRegistry).build();
    mongoClient = new MongoClient(new ServerAddress(), options);
    db = mongoClient.getDatabase("DutySchedulerDB");

Моят изходен код за този проект може да бъде намерен на https://github.com/desrepair/DutyScheduler. Отворен съм да отговоря на всички въпроси, които хората могат да имат.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB $orderBy

  2. Mongo групово намиране и актуализиране на полето за съответстващи документи в една заявка?

  3. MongoDB:Намерете минималния елемент в масива и го изтрийте

  4. Групов резултат по 15 минути времеви интервал в MongoDb

  5. Какво представлява грешката на Mongoose Прехвърлянето към ObjectId не бе успешно за стойност XXX на път _id?