1

I am using reactive MongoDb, and trying to implement Free Text search based on the weight

implementation("io.micronaut.mongodb:micronaut-mongo-reactive")

on below POJO

public class Product {
    @BsonProperty("_id")
    @BsonId
    private ObjectId id;
    private String name;
    private float price;
    private String description;
}

Tried this simple example

public Flowable<List<Product>> findByFreeText(String text) {
    LOG.info(String.format("Listener --> Listening value = %s", text));
    Flowable.fromPublisher(this.repository.getCollection("product", List.class)
            .find(new Document("$text", new Document("$search", text)
                    .append("$caseSensitive", false)
                    .append("$diacriticSensitive", false)))).subscribe(item -> {
                System.out.println(item);
            }, error -> {
                System.out.println(error);
            });
    return Flowable.just(List.of(new Product()));
}

I don't think this is the correct way of implementing the Free Text Search.

San Jaisy
  • 15,327
  • 34
  • 171
  • 290

1 Answers1

1

At first you don't need to have Flowable with List of Product because Flowable can manage more then one value unlike Single. So, it is enough to have Flowable<Product>. Then you can simply return the Flowable instance from find method.

Text search can be then implemented like this:

public Flowable<Product> findByFreeText(final String query) {
    return Flowable.fromPublisher(repository.getCollection("product", Product.class)
        .find(new Document("$text",
            new Document("$search", query)
                .append("$caseSensitive", false)
                .append("$diacriticSensitive", false)
        )));
}

Then it is up to the consumer of the method how it subscribes to the result Flowable. In controller you can directly return the Flowable instance. If you need to consume it somewhere in your code you can do subscribe() or blockingSubscribe() and so on.

And you can of course test it by JUnit like this:

@MicronautTest
class SomeServiceTest {
    @Inject
    SomeService service;

    @Test
    void findByFreeText() {
        service.findByFreeText("test")
            .test()
            .awaitCount(1)
            .assertNoErrors()
            .assertValue(p -> p.getName().contains("test"));
    }
}

Update: you can debug communication with MongoDB by setting this in logback.xml (Micronaut is using Logback as a default logging framework) logging config file:

<configuration>
    ....
    <logger name="org.mongodb" level="debug"/>
</configuration>

Then you will see this in the log file:

16:20:21.257 [Thread-5] DEBUG org.mongodb.driver.protocol.command - Sending command '{"find": "product", "filter": {"$text": {"$search": "test", "$caseSensitive": false, "$diacriticSensitive": false}}, "batchSize": 2147483647, "$db": "some-database"}' with request id 6 to database some-database on connection [connectionId{localValue:3, serverValue:1634}] to server localhost:27017
16:20:21.258 [Thread-8] DEBUG org.mongodb.driver.protocol.command - 16:20:21.258 [Thread-7] DEBUG org.mongodb.driver.protocol.command - Execution of command with request id 6 completed successfully in 2.11 ms on connection [connectionId{localValue:3, serverValue:1634}] to server localhost:27017

Then you can copy the command from log and try it in MongoDB CLI or you can install MongoDB Compass where you can play with that more and see whether the command is correct or not.

cgrim
  • 4,890
  • 1
  • 23
  • 42
  • Any idea how do I set the logger for the mongoDb in micronaut ?? The search is not working for me? I have update the code – San Jaisy Nov 01 '20 at 15:13
  • Is there any option to add on the application.yml file ? – San Jaisy Nov 01 '20 at 15:46
  • Can you please also help me with this https://stackoverflow.com/questions/64247414/reactive-and-non-blocking-method-micronaut-with-apache-kafka I am struggling from so long – San Jaisy Nov 01 '20 at 15:47
  • Add logger into _logback.xml_ file as described in the answer and watch the log file. You can then try the same command in MongoDB CLI or you can install [MongoDB Compass](https://www.mongodb.com/products/compass) where you can play with that more and see whether the command is correct. Do you really store `List` in the Mongo collection? Isn't it rather collection of `Product`? – cgrim Nov 02 '20 at 09:18
  • Yeah, it is a collection of products. – San Jaisy Nov 02 '20 at 12:13
  • thank you it is working, can you please help me return value in kafka producer from the listener as describe in this question https://stackoverflow.com/questions/64247414/reactive-and-non-blocking-method-micronaut-with-apache-kafka – San Jaisy Nov 02 '20 at 12:35
  • I don't have any experience with Kafka yet, but I'll look on it in next days ;-) – cgrim Nov 02 '20 at 12:39