Home > Enterprise >  How to replace one document with WebFlux and MongoDB Reactive frameworks?
How to replace one document with WebFlux and MongoDB Reactive frameworks?

Time:02-16

I have an old project that I would like to modernize using WebFlux and MongoDB Reactive frameworks but I'm absolutely stuck at the update method. I have no clue what to pass in the subscribe method. The replaceOne call returns a Publisher but how I should handle it? One of the tips I read was about using the SubscriberHelpers class from mongo-java-driver-reactivestreams but it's missing from the recent versions (4.4). Any help would be appreciated.

mongoDatabase.getCollection("players", Player.class).replaceOne(
    Filters.eq("email", player.getEmail()),
    player,
    new ReplaceOptions().upsert(true)
).subscribe( ??? );

Update: I created a DummySubscriber class to manage the subscription which seems working properly.

mongoDatabase.getCollection("players", Player.class).replaceOne(
    Filters.eq("email", player.getEmail()),
    player,
    new ReplaceOptions().upsert(true)
).subscribe(new DummySubscriber<>());

private static class DummySubscriber<T> implements Subscriber<T> {
    @Override
    public void onSubscribe(Subscription subscription) {
        subscription.request(Integer.MAX_VALUE);
    }

    @Override
    public void onNext(T t) {
    }

    @Override
    public void one rror(Throwable throwable) {
        System.out.println("Error while updating data");
    }

    @Override
    public void onComplete() {
        System.out.println("Data has been updated");
    }
}

CodePudding user response:

After looking at your example i could see that the problem is that you are not using the ReactiveMongoTemplate when doing your calls against the database.

You decided to use the raw MongoDatabase object, which is more low level which does not provide you with the webflux api.

MongoDatabase only implement the standard reactivestreams specification, which does only support something implementing Subscriber<T> as subscribers.

I recommend not using the low level MongoDatabase object and instead use the higher level abstractions.

If you are going to use spring webflux you should be using either the ReactiveRepositories that spring provides, or if you want to be low level use the ReactiveMongoTemplate

private final ReactiveMongoTemplate reactiveMongoTemplate;

@Autowired
public PlayerRepository(ReactiveMongoTemplate reactiveMongoTemplate) {
    this.reactiveMongoTemplate = reactiveMongoTemplate;
}


public void savePlayers(Player player) {
    final Query query = new Query();
    query.addCriteria(Criteria.where("email").is(player.getEmail()));

    final Update update = new Update();
    update.set("name", player.getName());
    update.set("email", player.getEmail());

    reactiveMongoTemplate.findAndModify(query, update, Player.class)
            .subscribe(
                updatedPlayer -> System.out.println("updated player"),
                error -> System.out.println("Something went wrong: "   error.getCause()),
                () -> System.out.println("update is finished"));
}

I strongly suggest you learn how to use regular MongoTemplate without webflux before you go on to use webflux and the ReactiveMongoTemplate

There are several tutorials, about using MongoTemplate and the ReactiveMongoTemplate

https://www.baeldung.com/spring-data-mongodb-reactive

https://hantsy.github.io/spring-reactive-sample/data/data-mongo.html

  • Related