2

I am trying to store an array of floats in MongoDB. This is a sample of what I tried to do:

    float floatArray[] = {1, 2, 3, 4 ..... , 10000};
    MongoCollection<Document> collection = database.getCollection(XMLUtils.getDatabaseCollectionName());

            Document doc = new Document("_id", edgeId)
                  .append("floatArray", floatArray);

            collection.insertOne(doc);

But this throws an error:

org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class [F.

I did some research and I found the following in one of their JIRA Tickets:

The Document class currently supports only List, not native Java array

And even though converting to List would work, I will be dealing with huge arrays (size 10k+) and running for loops to convert them to Lists would hurt performance since I will have millions of arrays.

Is there any other way to store java arrays in MongoDB that does not involve converting them to List?

EDIT: Please note that question asks for solution to store an array of floats in MongoDB without converting it to a List. Suggested possible duplicate question stores lists instead of arrays.

5
  • 2
    Possible duplicate of How to add an array to a MongoDB document using Java? Commented Apr 25, 2018 at 18:52
  • 2
    Please see edit. Question specifies storing an array of floats without converting it to list. Suggested solution on possible duplicate stores lists to have an "array" format in the db since this is what was desired by the person who asked the possible duplicate question. I need to store actual arrays into mongodb without converting them to list. Commented Apr 25, 2018 at 19:12
  • 2
    Well, the docs can't get any more clear than "The Document class currently supports only List, not native Java array", can they? I don't know what you expect anyone on SO to say -- the way to save a collection in MongoDB is to use a List. Sorry, I don't think you're going to find a solution to this without writing your own Mongo connector. Commented Apr 25, 2018 at 21:45
  • Thank you for your answer. Would this be doable by writing my own Mongo connector? Any chance you can point me on the right direction on doing this? I'm new to Mongo. Commented Apr 25, 2018 at 22:08
  • Actually you don't need to write a connector. A Codec will do just fine. Please see my answer below Commented Aug 24, 2018 at 15:19

1 Answer 1

0

Don't despair, as with most OR related things in mongo you can always write yourself a codec. Would have been useful to provide some details how you currently handle your OR mapping, but I found the docs or the implementation of the native codecs (especially DocumentCodec) very helpful in figuring out how to implement and use them.

This is a codec I am using to persist an array of floats without making use of a Collection. Please note, that this always creates a float[] array of fixed size. If you have different needs, you would still need to figure out a way to determine and preallocate the needed memory. Code below will fail badly if you try to store larger arrays than it expects. Secondly, afaik mongo does not store floats, but doubles, so there will inevitably be some conversion.

AbstractCodec is our own implementation of commonly used methods e.g. readValue(), writeObject() to store and read various types. They were heavily inspired by the java driver implementation, so that should be a good starting point if codecs are new to you.

public class WaveformCodec extends AbstractCodec implements Codec<Waveform> {

    public WaveformCodec(CodecRegistry registry, BsonTypeClassMap bsonTypeClassMap) {
        super(registry, bsonTypeClassMap);
    }

    @Override
    public Waveform decode(BsonReader reader, DecoderContext decoderContext) {

        ObjectId id = null;
        float[] data = new float[5120];

        reader.readStartDocument();

        while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
            String fieldName = reader.readName();
            switch (fieldName) {
                case "_id":
                    id = (ObjectId) readValue(reader, ObjectId.class, decoderContext);
                    break;
                case "data":
                    reader.readStartArray();
                    int i = 0;
                    while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
                        data[i++] = (float) reader.readDouble();
                    }
                    reader.readEndArray();
                    break;
                default:
                    throw new RuntimeException("unknown field in WaveformCodec: " + fieldName);
            }
        }
        reader.readEndDocument();
        return new Waveform(id, data);
    }

    @Override
    public void encode(BsonWriter writer, Waveform waveform, EncoderContext encoderContext) {
        writer.writeStartDocument();

        writeObject(writer, "_id", ObjectId.class, waveform.getId(), encoderContext);

        writer.writeName("data");
        writer.writeStartArray();
        for (float value : waveform.getData()) {
            writer.writeDouble(value);
        }
        writer.writeEndArray();

        writer.writeEndDocument();
    }

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

And this is the class we are effectively persisting:

public class Waveform {
    private ObjectId id;
    private float[] data;

    public Waveform(ObjectId id, float[] data) {
        this.id = id;
        this.data = data;
    }

    public ObjectId getId() {
        return id;
    }

    public void setId(ObjectId id) {
        this.id = id;
    }

    public float[] getData() {
        return data;
    }
}

Now you just need to register your codec with the driver, and you should be able to enjoy typed collections.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.