Reputation: 21258
I have the following documents in my Mongo database (_ids skipped):
> db.names.find({})
{ "name": "John" }
{ "name": "Jack" }
{ "name": "Johny" }
{ "name": "Jenny" }
I have created the 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
So it behaves like a smart regular expression. Now I want to implement such 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 works exactly as I would have defined findByNameRegex
method in Spring data repository. How to implement the findByNameLike
behavior?
Why I need this: When I need filtering my collection by many attributes (e.g. by name only, by name and surname, by name and postal code, by name, surname and postal code etc.) its easier for me to support queries as parameters rather than create many very-long-named methods in repository.
Upvotes: 5
Views: 9823
Reputation: 21258
Actually, there is a simple method toLikeRegex that converts all *
to .*
. Together with catching invalid regular expressions, my custom implementation may 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 the same as Spring Data repository does.
Update 19 Apr 2016
There is a MongoRegexCreator
class since 1.9.0.RELEASE that provides a toRegularExpression
method.
String regex = MongoRegexCreator.INSTANCE
.toRegularExpression(userString, Part.Type.EXISTS);
Upvotes: 3