sql >> Databasteknik >  >> NoSQL >> MongoDB

MongoDB BSON-codec används inte vid kodning av objekt

Efter flera dagars research har jag hittat en lösning.

DutyBlockCodec beror på LocalDateCodec (som jag skapade) för att koda/avkoda. Detta beroende är inte tillfredsställt bara genom att lägga till de två kodekarna i samma codec-register. Lösningen är att skicka ett CodecRegistry objekt som innehåller codecs som DutyBlockCodec beror på (t.ex. ett CodecRegistry som innehåller LocalDateCodec ) till DutyBlockCodec s konstruktor, som lagras som en medlemsvariabel. För att använda LocalDateCodec för att koda använder jag EncoderContext.encodeWithChildContext() metod som skickar in codec, writer och element för att koda. Dessutom skriver jag enskilda fält istället för att skriva ett Document som en String (som i min ursprungliga kod). Alltså DutyBlock codec ser ut så här:

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 beror på en annan codec och kräver därför ett CodecRegistry ska skickas in på dess konstruktör. Även om jag tror att det är möjligt att skapa ett CodecRegistry med LocalDateCodec , skicka sedan detta som ett argument till DutyBlockCodec s konstruktor och skapa sedan ett annat CodecRegistry som innehåller både LocalDateCodec och DutyBlockCodec , detta är ganska förvirrande, och MongoDB tillhandahåller en funktionalitet, CodecProvider för att underlätta denna process.

Använda CodecProvider gränssnitt skrev jag en 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;
    }
}

Jag lade till dessa CodecProviders till MongoDB-klienten med hjälp av CodecRegistries.fromProviders() metod.

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");

Min källkod för detta projekt finns på https://github.com/desrepair/DutySchedulerJag är öppen för att svara på alla frågor som folk kan ha.



  1. skillnad mellan aggregat ($match) och fynd, i MongoDB?

  2. Hur man summerar värdet av en nyckel över alla dokument i en MongoDB-samling

  3. MongoDB BSON-codec används inte vid kodning av objekt

  4. Att fullända konsten att automatisera och hantera de mest populära databaserna med öppen källkod:2017 @ Severalnines