Search code examples
javamongodbmongodb-querymongodb-java

MongoDB Java client using $regex with $in


I am using the MongoDB Java client to query data:

    <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongodb-driver</artifactId>
        <version>3.5.0</version>
    </dependency>

The server version is 3.4.10.

When using the MongoDB shell, I can successfully query using:

db.c1.find(
    { title: { $in: [/test/,/demo/] } },
    { title:1 }
)

But when using the Java driver it does not work. For example:

List<String> keywords = new ArrayList<>();
keywords.add("/test/");
keywords.add("/demo/");
Document titleRegEx = new Document("$in", keywords);

Document filter = new Document("title", titleRegEx);

Document firstDoc = coll.find(filter).first();

logger.info("firstDoc: {}", firstDoc);

Please help me out.


Solution

  • If you profile the MongoDB calls you'll see that this 'find statement' ...

    List<String> keywords = new ArrayList<>();
    keywords.add("/test/");
    keywords.add("/demo/");
    Document titleRegEx = new Document("$in", keywords);
    
    Document filter = new Document("title", titleRegEx);
    
    Document firstDoc = coll.find(filter).first();
    

    ... causes the following filter to be submitted to MongoDB:

    filter: { title: { $in: [ "/test/", "/demo/" ] } } }
    

    Note the value of the $in document; instead of $in: [/test/,/demo/] it is: $in: [ "/test/", "/demo/" ]. So, it is performing exact string matches on "/test/" and "/demo/" rather than regex matches. This explains why this 'find statement' returns nothing.

    You engage a regex search when using the Java driver like so:

    Filters.regex("title", "test")
    

    The MongoDB Java driver does not allow you to supply a collection of Bson instances for $in so if you want to search for documents which match one of the elements in this 'in' list: /test/, /demo/ then you have to form an OR query. For example:

     Bson filter = Filters.or(Filters.regex("title", "test"), Filters.regex("title", "demo"));
    
     FindIterable<Document> documents = collection.find(filter);
    

    If you profile the MongoDB calls you'll see that the above code causes the following 'find statement' to be executed on MongoDB:

    find { find: "posts", filter: { $or: [ { title: /test/ }, { title: /demo/ } ] } }
    

    This is functionally equivalent to the command you showed in your question.