sql >> Database teknologi >  >> NoSQL >> MongoDB

MongoDB BSON-codec bruges ikke under kodning af objekt

Efter flere dages research har jeg fundet en løsning.

DutyBlockCodec afhænger af LocalDateCodec (som jeg oprettede) for at indkode/afkode. Denne afhængighed tilfredsstilles ikke blot ved at tilføje de to codecs til det samme codec-register. Løsningen er at sende et CodecRegistry objekt, der indeholder codecs, der DutyBlockCodec afhænger af (f.eks. et CodecRegistry indeholdende LocalDateCodec ) til DutyBlockCodec 's konstruktør, som er gemt som en medlemsvariabel. For at bruge LocalDateCodec for at kode bruger jeg EncoderContext.encodeWithChildContext() metode, der sender codec, writer og element til indkodning. Derudover skriver jeg individuelle felter i stedet for at skrive et Document som en String (som i min originale kode). Således DutyBlock codec ender med at se sådan her ud:

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 afhænger af et andet codec, og kræver derfor et CodecRegistry skal videregives til sin konstruktør. Selvom jeg tror, ​​det er muligt at oprette et CodecRegistry med LocalDateCodec , så send dette som et argument til DutyBlockCodec 's constructor, og opret derefter endnu et CodecRegistry indeholdende både LocalDateCodec og DutyBlockCodec , dette er ret forvirrende, og MongoDB giver en funktionalitet, CodecProvider for at lette denne proces.

Brug af CodecProvider interface, skrev jeg 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;
    }
}

Jeg tilføjede disse CodecProviders til MongoDB-klienten ved hjælp af CodecRegistries.fromProviders() metode.

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 kildekode til dette projekt kan findes på https://github.com/desrepair/DutySchedulerJeg er åben for at besvare alle spørgsmål, folk måtte have.



  1. Forespørg MongoDB med $and og Multiple $or

  2. Hvordan deler man session mellem NodeJs og PHP ved hjælp af Redis?

  3. Mongo Change Streams, der kører flere gange (en slags):Node-app, der kører flere forekomster

  4. MongoDB $log