infthi
infthi

Reputation: 557

Spring, MongoDB and upserts: works with one-by-one updates, fails with bulk updates

In my test code I first perform a regular upsert using MongoTemplate.upsert(). It correctly adds data to the DB, and the following document appears in the db, just as expected:

{ "_id" : 1, "elements" : [ { "payload" : "payload" } ] }

I then perform a similar upsert using BulkOperations. It fails with the following exception:

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

I thought these two calls should perform identically. Am I missing something in BulkOperations API? How can I make bulk operations to encode objects the same way regular operations do?

I use mongo-java-driver 3.3.0 (similar problem can also be observed on 2.14.3)

public class Main {
    public static void main(String[] args) throws UnknownHostException {
        MongoTemplate template = new MongoTemplate(new Mongo("localhost"), "local");

        // works
        template.upsert(makeQuery(1), makeUpdate(), Data.class);

        // fails miserably
        BulkOperations ops = template.bulkOps(BulkOperations.BulkMode.UNORDERED, Data.class);
        ops.upsert(makeQuery(2), makeUpdate());
        ops.execute();
    }

    private static Query makeQuery(int id) {
        return Query.query(Criteria.where("id").is(id));
    }

    private static Update makeUpdate() {
        Update update = new Update();
        update.set("elements", Collections.singletonList(new Element()));
        return update;
    }
}

@Document(collection = "test")
class Data {
    private int id = 1;
    private List<Element> elements;
}

class Element {
    private String payload = "payload";
}

Upvotes: 3

Views: 1405

Answers (1)

a.l.
a.l.

Reputation: 1135

It seems like there's a bug in spring-data-mongo when bulk update a List field, and the item in the List is not a scalar(like String, Integer). It complains there's no codes.

There one way to avoid it

private static Update makeUpdate() {
    Update update = new Update();
    update.set("elements", mongoConverter.convertToMongoType(Collections.singletonList(new Element())));
    return update;
}

where mongoConverter is a org.springframework.data.mongodb.core.convert.mongoConverter, and you can autowire a instance in your bean.

Upvotes: 1

Related Questions