Java helper functions - Query an array with a regex in an aggregation pipeline

I’m having trouble utilizing the MongoDB Java driver’s helper methods to simplify a query on my collection.

Goal: the user should be able to search all bookmarks by title (string), description (string), url (string), created date (Date), and in an array of tags (string[ ]).

The aggregation pipeline in Compass spat out this code, which DOES WORK to search the elements in the tags array:

new Document("tags",
    new Document("$elemMatch",
         new Document("$regex", keywords).append("$options", "i")))

I'd like to do something like this, but I can't seem to figure out the proper use of syntax to get it to work:

I’ve looked at the Java documentation for elemMatch and regex, but the method’s parameters don’t seem to work for this type of query :confused:

Filters.elemMatch("tags", Filters.regex("tags", keywords, "i"));

My whole function:

  public List<Bookmark> getBookmarksBySearchKeywords(String userId, String keywords) {
    if (userId == null || keywords == null) return null;

    List<Bson> pipeline = new ArrayList<>();
    Bson matchUserId = Aggregates.match(new Document("user_id", userId));
    Bson matchFields = Aggregates.match(Filters.or(
            Filters.regex("title", keywords, "i"),
            Filters.regex("description", keywords, "i"),
            Filters.regex("url", keywords, "i"),
            Filters.regex("dateCreated", keywords, "i"),
            new Document("tags",
                    new Document("$elemMatch",
                            new Document("$regex", keywords)
                                    .append("$options", "i")))
//            Filters.elemMatch("tags", Filters.regex("tags", keywords, "i"))
    ));
    Bson sortByTitle = Aggregates.sort(Sorts.ascending("title"));
    pipeline.add(matchUserId);
    pipeline.add(matchFields);
    pipeline.add(sortByTitle);

    List<Bookmark> bookmarks = bookmarksCollection.aggregate(pipeline).into(new ArrayList<>());
    return bookmarks;
  }

Here’s an example of a bookmark in the database. I also need to change the front-end Vue app to submit the dateCreated field as a Date, rather than a string!

Any help is greatly appreciated!

Hello @Ian_Goodwin, you can use this code to filter the tags array in your $match stage of the aggregation (worked with Java Driver v3.12.2 and MongoDB v4.2.8):

Filters.regex("tags", keywords, "i")

Please note the $elemMatch is not required in this case; $elemMatch is required when you are querying on multiple fields of a sub-document of an array field (for example, stock: [ { qty: 10, price: 5.85 }, { ... }, ], and if you are querying on both fields of the array field then use $elemMatch).

2 Likes

That makes sense. Thanks for helping me understand $elemMatch, that does the trick!

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.