How does Spring create its similar * queries in mango?

I have the following documents in my Mongo database (_ids missing):

> db.names.find({})
{ "name": "John" }
{ "name": "Jack" }
{ "name": "Johny" }
{ "name": "Jenny" }

      

I created a Spring data repository for this collection:

public interface NameRepository extends MongoRepository<Name, ObjectId> {
    Collection<Name> findByNameLike(String name);
}

      

The results are as follows:

nameRepository.findByNameLike("John"); // John, Johny
nameRepository.findByNameLike("John$"); // John
nameRepository.findByNameLike("J*ny"); // Johny, Jenny
nameRepository.findByNameLike("Jo?*ny"); // Johny, Jenny
nameRepository.findByNameLike("Jo[]]?*ny"); // empty, without error

      

Thus, it behaves like a smart regex. Now I want to implement this behavior myself:

class MyNameRepository {
    MongoOperations mongoOperations; // injected

    public Collection<Name> findByName(String like) {
        Query query = new Query();
        query.addCriteria(Criteria.where("name").regex(like));
        return mongoOperations.find(query, Name.class)
    }
}

      

But the behavior of my method is different:

myNameRepository.findByName("John"); // John, Johny
myNameRepository.findByName("John$"); // John
myNameRepository.findByName("J*ny"); // empty, without error
myNameRepository.findByName("Jo?*ny"); // error (invalid regex)
myNameRepository.findByName("Jo[]]?*ny"); // error (invalid regex)

      

So my custom methods work exactly the same as I would define a method findByNameRegex

in the Spring data repository. How do I implement the behavior findByNameLike

?

Why do I need this: When I need to filter my collection by many attributes (for example, first name only, first name and last name, first name and zip code, first name, last name and zip code, etc.), I find it easier to maintain queries as parameters rather than creating many multivalued methods in the repository.

+3


source to share


1 answer


There is actually a simple toLikeRegex method that converts everything *

to .*

. Along with looking for invalid regexps, my custom implementation might look like this:

class MyNameRepository {
    MongoOperations mongoOperations; // injected

    public Collection<Name> findByName(String like) {
        try{
            Query query = new Query();
            query.addCriteria(Criteria.where("name").regex(toLikeRegex(like)));
            return mongoOperations.find(query, Name.class);
        } catch(PatternSyntaxException e) {
            return Collections.emptyList();
        }
    }

    private String toLikeRegex(String source) {
        return source.replaceAll("\\*", ".*");
    }
}

      

and behaves just like the Spring Data Repository.




Update April 19, 2016

There is a class MongoRegexCreator

as of 1.9.0.RELEASE that provides a method toRegularExpression

.

String regex = MongoRegexCreator.INSTANCE
               .toRegularExpression(userString, Part.Type.EXISTS);

      

+1


source







All Articles