-1

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 onError(Throwable throwable) {
        System.out.println("Error while updating data");
    }

    @Override
    public void onComplete() {
        System.out.println("Data has been updated");
    }
}
Toerktumlare
  • 12,548
  • 3
  • 35
  • 54
Dimnox
  • 441
  • 1
  • 6
  • 13
  • your application is a `Producer` whomever initiates the call Is the `Consumer` and the `Consumer`will `Subscribe` to the `Producer`So what does this mean? well it means that the webpage, is the `consumer`or another `service`since they initated the call. And your application `produces` which means YOU should not `subscribe` you should instead return the `Mono/Flux` all the way out to the client, so that the client can `subscribe`(in this case, the framework (webflux)) will handle the subscription when someone calls your service. So you should not use subscribe at all in this scenario. – Toerktumlare Feb 14 '22 at 23:01
  • so remove it and instead return the returned value all the way out the api. – Toerktumlare Feb 14 '22 at 23:02
  • These may be helpful: [How to update field type in a document using Java MongoDB Reactive driver?](https://stackoverflow.com/questions/59542115/how-to-update-field-type-in-a-document-using-java-mongodb-reactive-driver/59547016#59547016) _and_ https://stackoverflow.com/questions/65327113/mongodb-java-driver-reactive-with-pojo-mapping-find-list-of-documents-in-a-type/65336819#65336819 . Also, see this [MongoDB Java Reactive Streams help](https://www.mongodb.com/community/forums/t/mongodb-java-reactive-streams-help/7352). – prasad_ Feb 15 '22 at 06:09
  • Thanks for your advices but I'm afraid none of them work in this particular case. Player update is a Spring scheduled task so I need to manage the subscription inside the project. SubscriberHelpers could help but the mongo-java-driver-reactivestreams is already EOL and this class has been removed from mongodb-driver-core/reactivestreams. I'm thinking of creating a ReactiveMongoRepository interface and handle the save method there but it's more like a workaround than a real solution. – Dimnox Feb 15 '22 at 08:12
  • `Player update is a Spring scheduled task so I need to manage the subscription inside the project` if you want people on stack overflow to help you, you should post full context about the problem. None of this information was/is provided in the original question, and we are not mind readers, and we can only answer questions that actually include all know pieces of the question. Update your question with ALL relevant information instead of slowly adding more and more information in comments. Good luck – Toerktumlare Feb 15 '22 at 16:39

1 Answers1

1

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

Toerktumlare
  • 12,548
  • 3
  • 35
  • 54
  • I totally agree, it's much clener and that was my first idea as well but it throws a compile error that I couldn't resolve. Here is the error message I got: java: method subscribe in interface org.reactivestreams.Publisher cannot be applied to given types; required: org.reactivestreams.Subscriber super com.mongodb.client.result.InsertOneResult> found: ()->System[...]ata"),()->System[...]ata"),()->System[...]ted") reason: actual and formal argument lists differ in length – Dimnox Feb 15 '22 at 17:55
  • i have updated the code example, that is because your earlier function apparently returns something. – Toerktumlare Feb 15 '22 at 18:07
  • I really appreciate your help but it's still not working. I understand that a simple lambda expression should be enough to resolve it (like: subscribe(i -> System.out.println(i)) but it throws a compile error. I've tried your updated code but it causes the same error in compile time. – Dimnox Feb 15 '22 at 18:28
  • please just dont say that you get a "compiler error" im not a mind reader so i cant help you unless you tell me what compiler error you are getting from the updated code. And it cant give the same, because the code is different, which means the error message must be different, what is returned in "found" is different. The code compiles at my end so your implementation must clearly be wrong. – Toerktumlare Feb 15 '22 at 18:41
  • Could you have a look at this demo project, please? If you open the PlayerReporistory class you can reproduce the compilation error: https://github.com/aszidien/mongo-demo – Dimnox Feb 15 '22 at 19:04
  • i have looked and updated my answer – Toerktumlare Feb 15 '22 at 20:43