Escape MongoDB regex character in Spring SpEL - getting SpelParseException - java

I'm trying to override the MongoRepository::findAll() method to define the custom #Query. I am following the SpEL JPA Query support docs to have similar logic in MongoRepository to check for user role and create a dynamic query to fetch the authorized records.
I've the following method setup in my BlogRepository which extends MongoRepository:
#Query("{ user_id : ?#{ hasRole('ROLE_ADMIN') ? /./ : principal.userId } } ")
#Override
Page<Blog> findAll(Pageable pageable);
I get the following error from this method:
org.springframework.expression.spel.SpelParseException: EL1049E:(pos 31): Unexpected data after '.': 'div(/)'
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.raiseInternalException(InternalSpelExpressionParser.java:988)
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.eatDottedNode(InternalSpelExpressionParser.java:407)
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.maybeEatNode(InternalSpelExpressionParser.java:360)
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.eatPrimaryExpression(InternalSpelExpressionParser.java:345)
at org.springframework.expression.spel.standard.InternalSpelExpressionParser.eatUnaryExpression(InternalSpelExpressionParser.java:337)
As the below mongo query runs and retuns the desired values, I believe, I just need to escape the /./ character so that SpEL doesn't try to parse it.
{ 'user_id' : /./ }
I couldn't find a escape character for SpEL but played with the following options and still similar kind of parse exception is coming up:
'/./'
#{/./} -- wraping with SpEL expression
.
/.*.*/
Could you help me out?

I got it working :
#Query(" ?#{ hasRole('ROLE_ADMIN') ? '{}' : {'user_id' : principal.userId } } ")

probably you can use escape function like
%?#{escape(...)}

Related

How to call oracle function from spring boot application?

My requirement is i need to call oracle function from spring boot application without using NATIVE query.
below is my oracle function which is taking Date as input
create or replace FUNCTION todate(src_dt IN date)
RETURN date
is
BEGIN
RETURN(to_date(src_dt));
END;
i was searching solution on internet but so far did't find. people are saying some custom dialect need to create but not found any perfect step by step link.
below is my java code :-
Query query1 = entityManager.createQuery("select todate(ActSubT.createdDt) from ActSubT ActSubT");
List<Object> result=query1.getResultList();
this code should run , as of now its giving error as todate is oracle function and i haven't configured anything in application.yml file.
below error i am getting
java.lang.IllegalArgumentException: org.hibernate.QueryException:
No data type for node:
org.hibernate.hql.internal.ast.tree.MethodNode
\-[METHOD_CALL] MethodNode: '('
+-[METHOD_NAME] IdentNode: 'todate' {originalText=todate}
Please help
I am able to solve my issue .
step 1 :- i created custom dialect, below is my code..
public class CustomDialect extends Oracle12cDialect {
public CustomDialect() {
super();
// CustomFunction implements SqlFunction
// registerFunction("custom_function", new CustomFunction());
// or use StandardSQLFunction; useful for coalesce
registerFunction("todate", new StandardSQLFunction("todate", StandardBasicTypes.DATE));
}
}
Step 2 :- now i am calling todate function , below is the Java code
Query query1 = entityManager.createQuery("select function('todate',ActSubT.createdDt) from ActSubT ActSubT where ActSubT.id=1105619");
Object resulth=query1.getSingleResult();
Step 3 :- this entry we need to put in application.poperties / application.yml
# Allows Hibernate to generate SQL optimized for a particular DBMS
spring.jpa.properties.hibernate.dialect = com.sbill.app.config.CustomDialect
That's all now i can call db function with java code.

Phrase suggester collate query in java api

The PhraseSuggestionBuilder in elasticsearch java API has a collateQuery method that takes a String as input. but there is a problem, this code:
collateQuery("\"match\": {\"title.phrase\" : \"{{suggestion}}\"}")
will result in something like this:
"collate" : {
"query" : "\"match\": {\"title\" : \"{{suggeston}}\"}"
}
as you see the escaped quotes are still there and I get "failed to derive xcontent" error. I can not find an example of collateQuery using java api. what should I do?
I solved this problem in the Java API by building the collate query with the conventional QueryBuilder, such as:
MatchQueryBuilder cq = QueryBuilders.matchQuery("title", "some text");
Then, I added it to the collate by calling its toString method:
String queryText = "the user query";
SuggestBuilder suggest = new SuggestBuilder()
.setGlobalText(queryText)
.addSuggestion("body",
SuggestBuilders
.phraseSuggestion("your.field")
.size(3)
.gramSize(3)
.addCandidateGenerator(new DirectCandidateGeneratorBuilder("your.field")
.suggestMode("missing"))
.collateQuery(cq.toString())
.collatePrune(true));
that toString() call seems to push the query through Elasticsearch's XContentBuilder, so you don't need to worry about backslash escaping and so on.

Getting error in Excel to MongoDB JSON convert using Java [duplicate]

I figured out that of course . and SPACE aren't allowed. Are there other forbidden characters ?
You can use any (UTF8) character in the field name which aren't
special (contains ".", or starts with "$").
https://jira.mongodb.org/browse/SERVER-3229
https://stackoverflow.com/a/7976235/311220
It's generally best to stick with lowercase alphanumeric with underscores though.
Something else to look out for is the fact that you can make a property name called "query" but then use query operators on it, making it awkward to do a large number of queries.
Example:
Insert document with a property named
db.coll.insert({ query: 'foo' });
Equality query works:
db.coll.findOne({ query: 'foo' });
Not equal ($ne) does not:
db.coll.findOne({ query: { $ne: 'bar' } });

How to use Regex keyword in Spring Data Repository Method

I am currently using spring-data-jpa version 1.9.4.
I have a MySql table with columns project(integer), summary(varchar), and description(varchar).
I have a regex that I would like to use to search the summary and/or description field meaning that if it finds it in summary does not need to apply regex to description.
The repository method I am attempting to use is:
List<Issue> findByProjectAndSummaryOrDescriptionRegex(long project, String regex)
The error I am receiving is:
java.lang.IllegalArgumentException: Unsupported keyword REGEX (1):
[MatchesRegex, Matches, Regex]
It is difficult in my company environment to update/upgrade versions, so if the issue is NOT my syntax but rather the then if someone knows which version now supports 'Regex' for query derivation or where I could find that specific information I would be grateful. I have looked at the Changelog and it appears that 1.9.4 should support but it appears not.
Thanks for your help!
JD
EDIT 1: I am aware of the #Query annotation but have been asked by my lead to only use that as a last resort if I cannot find the correct version which supports keyword REGEX [MatchesRegex, Matches, Regex]
I would recommend using native query (with #Query annotation) if the Spring data syntax does not work, e.g.:
#Query(nativeQuery=true, value="SELECT * FROM table WHERE project = ?1 AND (summary regexp ?2 OR description regexp ?2)")
List<Issue> findByProjectAndSummaryOrDescription(long project, String regex);
Update
If native query is not an option then (a) could you try it with single column and see if that works and (b) could you try by appending regex to both the columns, e.g.:
List<Issue> findByProjectAndDescriptionRegex(long project, String regex);
List<Issue> findByProjectAndSummaryRegexOrDescriptionRegex(long project, String regex, String regex);
In a followup, I discovered by doing some digging that the authoratative list will reside in the org.springframework.data.jpa.repository.query.JpaQueryCreator class. So for future folks that want to know which keywords from the 'Documented' list are ACTUALLY implemented, look inside JpaQueryCreator and you will the keywords supported as case arguments inside a switch!
Hope this helps!
PS - as suspected, REGEX was not supported in my version
try tu use #Query with param nativeQuery = true inside You can use database regexp_like function :
#Query(value = "select t.* from TABLE_NAME t where regexp_like(t.column, ?1)", nativeQuery = true)
Documentation :
https://www.techonthenet.com/oracle/regexp_like.php

Spring mongo query collection on property with underscore char

I'm building a query to retrieve elements from a mongo collection, using MongoTemplate. The query criteria contains a property with an underscore, that somehow is replaced with '._', making the query always return 0 elements.
Criteria matchingCriteria = Criteria
.where("entries").elemMatch(Criteria.where("app_id").is(appId))
Looking to the logs I can see the generated query as follows:
o.s.data.mongodb.core.MongoTemplate: find using query: { "entries" : { "$elemMatch" : { "app._id" : "5834718ab0"}}} fields: null for class: Ranking in collection: ranking
I've already tried with BasicQuery, slashing underscore with '\\', and using the unicode “app\u005Fid". None of them worked. It's important to note that a collection with name "app" exists in my database.
The behaviour doesn't look standard. When I use another property with an underscore the value is not replaced:
Criteria matchingCriteria = Criteria .where("entries").elemMatch(Criteria.where("unique_app_id").‌​is(appId))
The logs:
o.s.data.mongodb.core.MongoTemplate find using query: { "entries" : { "$elemMatch" : { "unique_app_id" : "1131706359"}}} fields: null for class: class Ranking in collection: ranking
entries is an array with collection with the following format:
{
"instanceId" : "654ba2d16579e",
"app_id" : "583471adb0",
"unique_app_id" : "554577506",
"value" : 169
}
It's worth mentioning that the same query (without the underscore replacement) works fine in a mongo IDE (Robomongo in this case).
I'm using spring-boot-starter-data-mongodb 1.4.1.RELEASE.
I'm really out of ideas right now.
Any suggestion ?
Per section 3.4.3 of this Spring Data Commons documentation:
As we treat underscore as a reserved character we stongly advise to
follow standard Java naming conventions (i.e. not using underscores in
property names but camel case instead).
I don't believe you can use an underscore character in the middle of an element's name using Spring. Manual references are named after the referenced collection. Use the document type (collection name in singular) followed by _id ( <document>_id ). This is the only case where you can use underscore in the middle.
Update: Here is an existing pull request for the exact behavior you're seeing, as well as Spring's bug tracker for it.
From the Mongo shell, I can execute the following query with success:
> db.app.findOne({ "entries" : { "$elemMatch" : { "app_id" : "1"}}})
{
"_id" : ObjectId("58a5bc6afa8dd4ae3097d5f7"),
"name" : "Keith",
"entries" : [
{
"instanceId" : "654ba2d16579e",
"app_id" : "1"
}
]
}
So, perhaps the Spring API doesn't split when it finds multiple _ tokens when parsing a criteria, but does split for traversal when parsing one.

Categories

Resources