MongoTemplate - where with JS function - java

I need to query the db with the $where operator from Java Spring mongoTemplate.
This is the query:
db.myCollection.find( {$where : function () {
for (var index in this.*someKey*){
if (index.indexOf(*someValue*) > -1){
return this;
}
}
}})
But the mongoTemplate where operator expects to receive key not java script string function. Is there anyway around this?

I ended up using Spring MongoDB repositories(I needed paging as well)
public interface MyCollectionRepository extends PagingAndSortingRepository<MyCollectionClass, String> {
#Query("{$where : ?0}")
Page<MyCollectionClass> findSomething(String whereQuery, Pageable pageable);
.....
}
And
public static String whereQuery(String someValue){
return "function() {" +
"for (var index in this.*someKey*){" +
"if (index.indexOf(\""+ someValue+"\") > -1){" +
"return this;" +
"}" +
"}" +
"}";
}

Related

How to get data from query string in Java Spring boot REST

We have a requirement to read data after '?' in service-url in Spring boot REST API.
For example, We exposed a service called sampleService and GET URL for this is
http://www.myservices.com/api/sampleServce
And clients will pass the data as http://www.myservices.com/api/sampleServce?dynamicdata
So we have to read that "dynamicdata" in my sample service and process.
Please let me know the possibilities.
GET: http://localhost:8080/api/foos?id=abc here the query string is id=abc . Now to extract the value of id, you can use the code something like this.
#GetMapping("/api/foos")
#ResponseBody
public String getFoos(#RequestParam String id) {
return "ID: " + id;
}
GET: http://www.myservices.com/api/sampleServce?dynamicdata is incorrect. Either it should be http://www.myservices.com/api/sampleServce/dynamicdata (PathVariable) or http://www.myservices.com/api/sampleServce?title=dynamicdata (RequestParam)
GET: http://www.myservices.com/api/sampleServce/dynamicdata to extract dynamicdata, you can use code something like
#GetMapping("/api/sampleServce/{id}")
#ResponseBody
public String getFooById(#PathVariable String id) {
return "ID: " + id; // here id = "dynamicdata"
}
GET: http://www.myservices.com/api/sampleServce?title=dynamicdata to extract title, you can use code something like
#GetMapping("/api/sampleServce")
#ResponseBody
public String getFoos(#RequestParam String title) {
return "title: " + title; // title="dynamicdata"
}
dynamicdata is path param, it cannot be placed after ?. It should be something like this:
http://www.myservices.com/api/dynamicdata/sampleServce
Check when and how to use query or path parameters
Accept dynamic data through request param:
#GetMapping("/api/sampleServce")
public void test(#RequestParam Map<String, String> dynamicdata) {
System.out.println(dynamicdata.keySet()); //http://localhost:9001/dag-backend/api/sampleServce?test&test11
Optional<String> data = dynamicdata.keySet().stream().findFirst();
String value = data.isPresent() ? data.get() : null;
System.out.println(value); //http://localhost:9001/dag-backend/api/sampleServce?test
}
URLs:
http://www.myservices.com/api/sampleServce?dynamicdata
http://www.myservices.com/api/sampleServce?dynamicdata&12344&1212
http://www.myservices.com/api/sampleServce?$999900&124434&234
You can add an HttpServletRequest object to your mapped method signature:
#RequestMapping("/api/sampleServce")
public Object sampleServce (HttpServletRequest request) {
//print everything after the question mark:
System.out.println("queryString: " + request.getQueryString());
//print key value pairs:
Enumeration<String> params = request.getParameterNames();
while(params.hasMoreElements()){
String paramName = params.nextElement();
String paramValue = request.getParameter(paramName);
System.out.println("name: " + paramName);
System.out.println("value: " + paramValue);
}
return request.getQueryString();
}

Transactions from ArangoDB java driver fails to change anything in the database

I am trying to send a transaction through the Java driver in my spring application.
The following is the simplified code.
#Test
public void rawTransactionTest(){
var appContext = new AnnotationConfigApplicationContext(DataLoaderApplication.class);
var arangoOperations = appContext.getBean(ArangoOperations.class);
String action = "function(){\n" +
" db = require(\"#arangodb\").db; \n" +
"db._query(\"LET doc = {title: \\\"Hello\\\"} "+
"UPSERT { _key: doc._key } INSERT doc._key == null ? UNSET(doc, \\\"_key\\\") : doc " +
"REPLACE doc IN Books OPTIONS { ignoreRevs: false } RETURN NEW\");\n" +
"return \"Success\"; \n" +
"}";
System.out.println(action);
var tOpts = new TransactionOptions();
tOpts.writeCollections("Books");
tOpts.waitForSync(true);
var result = arangoOperations.driver().db().transaction(action, String.class, tOpts);
System.out.println("Commit");
}
This returns the return value "Success" in the variable result. But the database remains unchanged. Doing the same thing in ArangoShell works perfectly fine. The ArangoShell code is as follows -
db._executeTransaction({
collections: {
write: ["Books"]
},
action: function(){
db = require("#arangodb").db;
db._query("LET doc = {title: \"Hello\"} UPSERT { _key: doc._key } "+
"INSERT doc._key == null ? UNSET(doc, \"_key\") : doc REPLACE doc"+
" IN Books OPTIONS { ignoreRevs: false } RETURN NEW");
return "Success";
}
});
This code works fine from the shell. Other non-transaction queries work fine from he same Spring-container.
What might be the problem?
The .db() only points to the _system database. Had to pass the database name to fix it.

SimpleJdbcCall always omits the first parameter in function calls

I'm trying to use the SimpleJdbcCall class to call functions in an Oracle package, but every call ignores the first input parameter.
My code looks like this:
SimpleJdbcCall call = new SimpleJdbcCall(jdbcTemplate.getJdbcTemplate())
.withSchemaName("MY_SCHEMA")
.withCatalogName("MY_PACKAGE")
.withFunctionName("MY_FUNCTION")
.withoutProcedureColumnMetaDataAccess()
.declareParameters(new SqlParameter("FIRST_ARGUMENT", Types.VARCHAR), new SqlParameter("SECOND_ARGUMENT", Types.VARCHAR));
SqlParameterSource params = new MapSqlParameterSource().addValue("FIRST_ARGUMENT", "VALUE1").addValue("SECOND_ARGUMENT", "VALUE2");
Integer result = call.executeFunction(Integer.class, params);
with my function being:
FUNCTION MY_FUNCTION(FIRST_ARGUMENTvarchar2, SECOND_ARGUMENTvarchar2) RETURN number;
The stacktrace shows this kind of errors:
org.springframework.jdbc.BadSqlGrammarException: CallableStatementCallback; bad SQL grammar [{? = call MY_SCHEMA.MY_PACKAGE.MY_FUNCTION(?)}];
A parameter has been removed. A call to another function with just one parameter throws a similar error:
org.springframework.jdbc.BadSqlGrammarException: CallableStatementCallback; bad SQL grammar [{? = call MY_SCHEMA.MY_PACKAGE.MY_OTHER_FUNCTION()}];
I've tried debugging the Spring code, spring-boot-starter-jdbc:2.0.1.RELEASE (2.0.0 too), and I've come accross this code in the org.springframework.jdbc.core.metadata.CallMetaDataContext class, when composing the call:
if (isFunction() || isReturnValueRequired()) {
callString = "{? = call " +
(StringUtils.hasLength(catalogNameToUse) ? catalogNameToUse + "." : "") +
(StringUtils.hasLength(schemaNameToUse) ? schemaNameToUse + "." : "") +
procedureNameToUse + "(";
parameterCount = -1;
}
else {
callString = "{call " +
(StringUtils.hasLength(catalogNameToUse) ? catalogNameToUse + "." : "") +
(StringUtils.hasLength(schemaNameToUse) ? schemaNameToUse + "." : "") +
procedureNameToUse + "(";
}
for (SqlParameter parameter : this.callParameters) {
if (!(parameter.isResultsParameter())) {
if (parameterCount > 0) {
callString += ", ";
}
if (parameterCount >= 0) {
callString += createParameterBinding(parameter);
}
parameterCount++;
}
}
callString += ")}";
If I've understood the code, the first parameter will always be ommited, am I right?
Has anybody had success in this situation?
M. Deinum is right and the return parameter must be specified too, I expected Spring to automatically add it when working with functions.
My code now:
SimpleJdbcCall call = new SimpleJdbcCall(jdbcTemplate.getJdbcTemplate())
.withSchemaName("MY_SCHEMA")
.withCatalogName("MY_PACKAGE")
.withFunctionName("MY_FUNCTION")
.withoutProcedureColumnMetaDataAccess()
.declareParameters(new SqlOutParameter("return",Types.INTEGER)
,new SqlParameter("FIRST_ARGUMENT", Types.VARCHAR)
,new SqlParameter("SECOND_ARGUMENT", Types.VARCHAR));
SqlParameterSource params = new MapSqlParameterSource().addValue("FIRST_ARGUMENT", "VALUE1").addValue("SECOND_ARGUMENT", "VALUE2");
Integer result = call.executeFunction(Integer.class, params);

Send two parameters from angular UI in post method and handled by java API

Just need guidance...
From controller to service, variables are accessible. But not available when they are send to api side. (With one variable it's working perfectly fine)
The variable values are coming after some calculations.
Service.js code...
function MySvcFunction(value1, value2) {
console.log('value1 : ', value1); //printing value1
console.log('value2 : ', value2); //printing value2
return $http.post('http://' + api_url + value1, value2).then(
function (response) {
//manage success
},
function (error) {
//manage error;
});
}
Controller.js code...
$scope.someFunction = function(){
console.log('value1 : ', value1); //printing value1
console.log('value2 : ', value2); //printing value2
MySvcController.MySvcFunction($scope.value1, $scope.value2).then(
function (response) {
//display on screen
});
And now api code in java...
Scenario-1 exception (with two #RequestBody)
#PostMapping(value = "/api_url")
public ResponseEntity<Object> MyFunction(#RequestBody Integer value1, #RequestBody Integer value2) {
System.out.println("value1 : "+ value1);
System.out.println("value2 : "+ value2);
}
//Exception:
Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Stream closed; nested exception is java.io.IOException*/
Scenario-2 exception (with one #RequestBody)
#PostMapping(value = "/api_url")
public ResponseEntity<Object> MyFunction(#RequestBody Integer value1, Integer value2) {
System.out.println("value1 : "+ value1); //value1 : int val
System.out.println("value2 : "+ value2); //value2 : null
}
//Exception:
nested NullPointerException with root cause.
I got it working not sure whether right or not?
Controller.js
$scope.someFunction = function(){
var bothVar = {'value1': $scope.value1, 'value2': $scope.value2};
MySvcController.MySvcFunction(bothVar).then(
function (response) {
//display on screen
});
Service.js
function MySvcFunction(bothVar) {
return $http.post('http://' + api_url + bothVar).then(
function (response) {
//manage success
},
function (error) {
//manage error;
});
}
API side java code
#PostMapping(value = "/api_url")
public ResponseEntity<Object> suggestBreakfast(#RequestBody Map bothVar){
System.out.println("value1 is : "+ bothVar.get("value1"));
System.out.println("value2 is : "+ bothVar.get("value2"));
}
// And i am getting those two values here successfully

JOOQ Java 8 Schema is Abstract and cannot be instantiated

In the JOOQ documentation It says I can do this:
try (Connection c = getConnection()) {
String sql = "select schema_name, is_default " +
"from information_schema.schemata " +
"order by schema_name";
DSL.using(c)
.fetch(sql)
// We can use lambda expressions to map jOOQ Records
.map(rs -> new Schema(
rs.getValue("SCHEMA_NAME", String.class),
rs.getValue("IS_DEFAULT", boolean.class)
))
// ... and then profit from the new Collection methods
.forEach(System.out::println);
}
However when I do that I get the error "org.jooq.Schema is abstract; cannot be instantiated" - which if you look at documentation that's true.
So how in the world is the code in the example supposed to work?
Short answer : they are not using "org.jooq.Schema" in their example, but instead a static inner class.
If you scroll down at the bottom of the page you linked, they give github links to examples. The example you have is the SQL goodies one.
If you open SQLGoodies.java you'll notice a static inner class Schema at the top of the example class
static class Schema {
final String schemaName;
final boolean isDefault;
Schema(String schemaName, boolean isDefault) {
this.schemaName = schemaName;
this.isDefault = isDefault;
}
#Override
public String toString() {
return "Schema{" +
"schemaName='" + schemaName + '\'' +
", isDefault=" + isDefault +
'}';
}
}
Then scroll down and you'll find your example using the inner class :
DSL.using(c)
.fetch(sql)
.map(r -> new Schema(
r.getValue("SCHEMA_NAME", String.class),
r.getValue("IS_DEFAULT", boolean.class)
))

Categories