I have to do this flexible search query in a service Java class:
select sum({oe:totalPrice})
from {Order as or join CustomerOrderStatus as os on {or:CustomerOrderStatus}={os:pk}
join OrderEntry as oe on {or.pk}={oe.order}}
where {or:versionID} is null and {or:orderType} in (8796093066999)
and {or:company} in (8796093710341)
and {or:pointOfSale} in (8796097413125)
and {oe:ecCode} in ('13','14')
and {or:yearSeason} in (8796093066981)
and {os:code} not in ('CANCELED', 'NOT_APPROVED')
When I perform this query in the hybris administration console I correctly obtain:
1164.00000000
In my Java service class I wrote this:
private BigDecimal findGroupedOrdersData(String total, String uncDisc, String orderPromo,
Map<String, Object> queryParameters) {
BigDecimal aggregatedValue = new BigDecimal(0);
final StringBuilder queryBuilder = new StringBuilder();
queryBuilder.append("select sum({oe:").append(total).append("})");
queryBuilder.append(
" from {Order as or join CustomerOrderStatus as os on {or:CustomerOrderStatus}={os:pk} join OrderEntry as oe on {or.pk}={oe.order}}");
queryBuilder.append(" where {or:versionID} is null");
if (queryParameters != null && !queryParameters.isEmpty()) {
appendWhereClausesToBuilder(queryBuilder, queryParameters);
}
queryBuilder.append(" and {os:code} not in ('");
queryBuilder.append(CustomerOrderStatus.CANCELED.getCode()).append("', ");
queryBuilder.append("'").append(CustomerOrderStatus.NOT_APPROVED.getCode()).append("')");
FlexibleSearchQuery query = new FlexibleSearchQuery(queryBuilder.toString(), queryParameters);
List<BigDecimal> result = Lists.newArrayList();
query.setResultClassList(Arrays.asList(BigDecimal.class));
result = getFlexibleSearchService().<BigDecimal> search(query).getResult();
if (!result.isEmpty() && result.get(0) != null) {
aggregatedValue = result.get(0);
}
return aggregatedValue;
}
private void appendWhereClausesToBuilder(StringBuilder builder, Map<String, Object> params) {
if ((params == null) || (params.isEmpty()))
return;
for (String paramName : params.keySet()) {
builder.append(" and ");
if (paramName.equalsIgnoreCase("exitCollection")) {
builder.append("{oe:ecCode}").append(" in (?").append(paramName).append(")");
} else {
builder.append("{or:").append(paramName).append("}").append(" in (?").append(paramName).append(")");
}
}
}
The query string before the search(query).getResult() function is:
query: [select sum({oe:totalPrice}) from {Order as or join CustomerOrderStatus as os on {or:CustomerOrderStatus}={os:pk}
join OrderEntry as oe on {or.pk}={oe.order}} where {or:versionID} is null
and {or:orderType} in (?orderType) and {or:company} in (?company)
and {or:pointOfSale} in (?pointOfSale) and {oe:ecCode} in (?exitCollection)
and {or:yearSeason} in (?yearSeason) and {os:code} not in ('CANCELED', 'NOT_APPROVED')],
query parameters: [{orderType=OrderTypeModel (8796093230839),
pointOfSale=B2BUnitModel (8796097413125), company=CompanyModel (8796093710341),
exitCollection=[13, 14], yearSeason=YearSeasonModel (8796093066981)}]
but after the search(query) result is [null].
Why? Where I wrong in the Java code? Thanks.
In addition, if you want to disable restriction in your java code. You can do like this ..
#Autowired
private SearchRestrictionService searchRestrictionService;
private BigDecimal findGroupedOrdersData(String total, String uncDisc, String orderPromo,
Map<String, Object> queryParameters) {
searchRestrictionService.disableSearchRestrictions();
// You code here
searchRestrictionService.enableSearchRestrictions();
return aggregatedValue;
}
In the above code, You can disabled the search restriction and after the search result, you can again enable it.
OR
You can use sessionService to execute flexible search query in Local View. The method executeInLocalView can be used to execute code within an isolated session.
(SearchResult<? extends ItemModel>) sessionService.executeInLocalView(new SessionExecutionBody()
{
#Override
public Object execute()
{
sessionService.setAttribute(FlexibleSearch.DISABLE_RESTRICTIONS, Boolean.TRUE);
return flexibleSearchService.search(query);
}
});
Here you are setting DISABLE RESTRICTIONS = true which will run the query in admin context [Without Restriction].
Check this
Better i would suggest you to check what restriction exactly applying to your item type. You can simply check in Backoffice/HMC
Backoffice :
Go to System-> Personalization (SearchRestricion)
Search by Restricted Type
Check Filter Query and analysis your item data based on that.
You can also check its Principal (UserGroup) on which restriction applied.
To confirm, just check by disabling active flag.
Query in the code is running not under admin user (most likely).
And in this case the different search Restrictions are applied to the query.
You can see that the original query is changed:
start DB logging (/hac -> Monitoring -> Database -> JDBC logging);
run the query from the code;
stop DB logging and check log file.
More information: https://wiki.hybris.com/display/release5/Restrictions
In /hac console the admin user is usually used and restrictions will not be applied because of this.
As the statement looks ok to me i'm going to go with visibility of the data. Are you able to see all the items as whatever user you are running the query as? In the hac you would be admin obviously.
Related
I have 2 database one is mysql and other is postgree.
I tried to get postgree data from mysql transactional method.
#Transactional(value = "pg")
public List<String> getSubordinate(){
Query q1 = JPA.em().createNativeQuery("select vrs.subordinate_number, vrs.superior_number\n" +
"from view_reporting_structure vrs\n" +
"where vrs.superior_number = :personel_number");
q1.setParameter("personel_number","524261");
List<String> me = q1.getResultList();
return me;
}
}
from another method
#Transactional
public Result getOpenRequestList(){
Subordinate subordinate = new Subordinate();
List<String> subordinateData = subordinate.getSubordinate();
....
}
i got error
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'db_hcm.view_reporting_structure' doesn't exist
so my Postgre method recognized as mySQL transaction which is the view not exist in mySQL database. how do I get data from different presistence unit with 1 method?
I never did it (different databases), but I guess the following may work.
For example, you have the following data source definition in application.conf:
# MySql
db.mysql.driver=com.mysql.jdbc.Driver
... the rest of setting for db.mysql
# H2
db.postgre.driver=org.postgresql.Driver
... the rest of setting for db.postgre
Instead of using #Transactional annotation, manage a transaction explicitly and use JPA withTransaction API:
private static final String MYSQL_DB = "mysql";
private static final String POSTGRE_DB = "postgre";
public List<String> getSubordinate() {
JPA.withTransaction(MYSQL_DB, true/* this is read-only flag*/,
() -> {
Query q1 = JPA.em().createNativeQuery("select vrs.subordinate_number, vrs.superior_number\n" +
"from view_reporting_structure vrs\n" +
"where vrs.superior_number = :personel_number");
q1.setParameter("personel_number","524261");
List<String> me = q1.getResultList();
return me;
}
}
public Result getOpenRequestList(){
JPA.withTransaction(POSTGRE_DB, true/* this is read-only flag*/,
() -> {
Subordinate subordinate = new Subordinate();
List<String> subordinateData = subordinate.getSubordinate();
....
}
}
Note: I prefer always use withTransaction, since it allows better control of unhappy flow. You should wrap the call with try-catch. If JPA throws a run-time exception on commit, you can do proper error handling. In case of using #Transactional annotation, commit takes place after controller have finished and you cannot handle the error.
I'm using azure-documentdb java SDK in order to create and use "User Defined Functions (UDFs)"
So from the official documentation I finally find the way (with a Java client) on how to create an UDF:
String regexUdfJson = "{"
+ "id:\"REGEX_MATCH\","
+ "body:\"function (input, pattern) { return input.match(pattern) !== null; }\","
+ "}";
UserDefinedFunction udfREGEX = new UserDefinedFunction(regexUdfJson);
getDC().createUserDefinedFunction(
myCollection.getSelfLink(),
udfREGEX,
new RequestOptions());
And here is a sample query :
SELECT * FROM root r WHERE udf.REGEX_MATCH(r.name, "mytest_.*")
I had to create the UDF one time only because I got an exception if I try to recreate an existing UDF:
DocumentClientException: Message: {"Errors":["The input name presented is already taken. Ensure to provide a unique name property for this resource type."]}
How should I do to know if the UDF already exists ?
I try to use "readUserDefinedFunctions" function without success. Any example / other ideas ?
Maybe for the long term, should we suggest a "createOrReplaceUserDefinedFunction(...)" on azure feedback
You can check for existing UDFs by running query using queryUserDefinedFunctions.
Example:
List<UserDefinedFunction> udfs = client.queryUserDefinedFunctions(
myCollection.getSelfLink(),
new SqlQuerySpec("SELECT * FROM root r WHERE r.id=#id",
new SqlParameterCollection(new SqlParameter("#id", myUdfId))),
null).getQueryIterable().toList();
if (udfs.size() > 0) {
// Found UDF.
}
An answer for .NET users.
`var collectionAltLink = documentCollections["myCollection"].AltLink; // Target collection's AltLink
var udfLink = $"{collectionAltLink}/udfs/{sampleUdfId}"; // sampleUdfId is your UDF Id
var result = await _client.ReadUserDefinedFunctionAsync(udfLink);
var resource = result.Resource;
if (resource != null)
{
// The UDF with udfId exists
}`
Here _client is Azure's DocumentClient and documentCollections is a dictionary of your documentDb collections.
If there's no such UDF in the mentioned collection, the _client throws a NotFound exception.
Trying to use a similar example from the sample code found here
My sample function is:
void query()
{
String nodeResult = "";
String rows = "";
String resultString;
String columnsString;
System.out.println("In query");
// START SNIPPET: execute
ExecutionEngine engine = new ExecutionEngine( graphDb );
ExecutionResult result;
try ( Transaction ignored = graphDb.beginTx() )
{
result = engine.execute( "start n=node(*) where n.Name =~ '.*79.*' return n, n.Name" );
// END SNIPPET: execute
// START SNIPPET: items
Iterator<Node> n_column = result.columnAs( "n" );
for ( Node node : IteratorUtil.asIterable( n_column ) )
{
// note: we're grabbing the name property from the node,
// not from the n.name in this case.
nodeResult = node + ": " + node.getProperty( "Name" );
System.out.println("In for loop");
System.out.println(nodeResult);
}
// END SNIPPET: items
// START SNIPPET: columns
List<String> columns = result.columns();
// END SNIPPET: columns
// the result is now empty, get a new one
result = engine.execute( "start n=node(*) where n.Name =~ '.*79.*' return n, n.Name" );
// START SNIPPET: rows
for ( Map<String, Object> row : result )
{
for ( Entry<String, Object> column : row.entrySet() )
{
rows += column.getKey() + ": " + column.getValue() + "; ";
System.out.println("nested");
}
rows += "\n";
}
// END SNIPPET: rows
resultString = engine.execute( "start n=node(*) where n.Name =~ '.*79.*' return n.Name" ).dumpToString();
columnsString = columns.toString();
System.out.println(rows);
System.out.println(resultString);
System.out.println(columnsString);
System.out.println("leaving");
}
}
When I run this in the web console I get many results (as there are multiple nodes that have an attribute of Name that contains the pattern 79. Yet running this code returns no results. The debug print statements 'in loop' and 'nested' never print either. Thus this must mean there are not results found in the Iterator, yet that doesn't make sense.
And yes, I already checked and made sure that the graphDb variable is the same as the path for the web console. I have other code earlier that uses the same variable to write to the database.
EDIT - More info
If I place the contents of query in the same function that creates my data, I get the correct results. If I run the query by itself it returns nothing. It's almost as the query works only in the instance where I add the data and not if I come back to the database cold in a separate instance.
EDIT2 -
Here is a snippet of code that shows the bigger context of how it is being called and sharing the same DBHandle
package ContextEngine;
import ContextEngine.NeoHandle;
import java.util.LinkedList;
/*
* Class to handle streaming data from any coded source
*/
public class Streamer {
private NeoHandle myHandle;
private String contextType;
Streamer()
{
}
public void openStream(String contextType)
{
myHandle = new NeoHandle();
myHandle.createDb();
}
public void streamInput(String dataLine)
{
Context context = new Context();
/*
* get database instance
* write to database
* check for errors
* report errors & success
*/
System.out.println(dataLine);
//apply rules to data (make ContextRules do this, send type and string of data)
ContextRules contextRules = new ContextRules();
context = contextRules.processContextRules("Calls", dataLine);
//write data (using linked list from contextRules)
NeoProcessor processor = new NeoProcessor(myHandle);
processor.processContextData(context);
}
public void runQuery()
{
NeoProcessor processor = new NeoProcessor(myHandle);
processor.query();
}
public void closeStream()
{
/*
* close database instance
*/
myHandle.shutDown();
}
}
Now, if I call streamInput AND query in in the same instance (parent calls) the query returns results. If I only call query and do not enter ANY data in that instance (yet web console shows data for same query) I get nothing. Why would I have to create the Nodes and enter them into the database at runtime just to return a valid query. Shouldn't I ALWAYS get the same results with such a query?
You mention that you are using the Neo4j Browser, which comes with Neo4j. However, the example you posted is for Neo4j Embedded, which is the in-process version of Neo4j. Are you sure you are talking to the same database when you try your query in the Browser?
In order to talk to Neo4j Server from Java, I'd recommend looking at the Neo4j JDBC driver, which has good support for connecting to the Neo4j server from Java.
http://www.neo4j.org/develop/tools/jdbc
You can set up a simple connection by adding the Neo4j JDBC jar to your classpath, available here: https://github.com/neo4j-contrib/neo4j-jdbc/releases Then just use Neo4j as any JDBC driver:
Connection conn = DriverManager.getConnection("jdbc:neo4j://localhost:7474/");
ResultSet rs = conn.executeQuery("start n=node({id}) return id(n) as id", map("id", id));
while(rs.next()) {
System.out.println(rs.getLong("id"));
}
Refer to the JDBC documentation for more advanced usage.
To answer your question on why the data is not durably stored, it may be one of many reasons. I would attempt to incrementally scale back the complexity of the code to try and locate the culprit. For instance, until you've found your problem, do these one at a time:
Instead of looping through the result, print it using System.out.println(result.dumpToString());
Instead of the regex query, try just MATCH (n) RETURN n, to return all data in the database
Make sure the data you are seeing in the browser is not "old" data inserted earlier on, but really is an insert from your latest run of the Java program. You can verify this by deleting the data via the browser before running the Java program using MATCH (n) OPTIONAL MATCH (n)-[r]->() DELETE n,r;
Make sure you are actually working against the same database directories. You can verify this by leaving the server running. If you can still start your java program, unless your Java program is using the Neo4j REST Bindings, you are not using the same directory. Two Neo4j databases cannot run against the same database directory simultaneously.
I am trying to use querydsl for building dynamic queries for dynamic schemas. I am trying to get just the query instead of having to actually execute it.
So far I have faced two issues:
- The schema.table notation is absent. Instead I only get the table name.
- I have been able to get the query but it separates out the variables and puts '?' instead which is understandable. But I am wondering if there is some way to get fully materialized query including the parameters.
Here is my current attempt and result(I am using MySQLTemplates to create the configuration):
private SQLTemplates templates = new MySQLTemplates();
private Configuration configuration = new Configuration(templates);
String table = "sometable"
Path<Object> userPath = new PathImpl<Object>(Object.class, table);
StringPath usernamePath = Expressions.stringPath(userPath, "username");
NumberPath<Long> idPath = Expressions.numberPath(Long.class, userPath, "id");
SQLQuery sqlQuery = new SQLQuery(connection, configuration)
.from(userPath).where(idPath.eq(1l)).limit(10);
String query = sqlQuery.getSQL(usernamePath).getSQL();
return query;
And what I get is:
select sometable.username
from sometable
where sometable.id = ?
limit ?
What I wanted to get was:
select sometable.username
from someschema.sometable
where sometable.id = ?
limit ?
Update: I came up with this sort of hack to get parameters materialized(Not ideal and would love better solution) But still could not get Schema.Table notation to work:
Hack follows. Please suggest cleaner QueryDsl way of doing it:
String query = cleanQuery(sqlQuery.getSQL(usernamePath));
private String cleanQuery(SQLBindings bindings){
String query = bindings.getSQL();
for (Object binding : bindings.getBindings()) {
query = query.replaceFirst("\\?", binding.toString());
}
return query;
}
To enable schema printing use the following pattern
SQLTemplates templates = MySQLTemplates.builder()
.printSchema()
.build();
SQLTemplates subclasses were used before, but since some time the builder pattern is the official way to customize the templates http://www.querydsl.com/static/querydsl/3.3.1/reference/html/ch02s03.html#d0e904
And to enable direct serialization of literals use
//configuration level
configuration.setUseLiterals(true);
//query level
configuration.setUseLiterals(true);
Here is a full example
// configuration
SQLTemplates templates = MySQLTemplates.builder()
.printSchema()
.build();
Configuration configuration = new Configuration(templates);
// querying
SQLQuery sqlQuery = new SQLQuery(connection, configuration)
.from(userPath).where(idPath.eq(1l)).limit(10);
sqlQuery.setUseLiterals(true);
String query = sqlQuery.getSQL(usernamePath).getSQL();
If you always just want the SQL query string out, move setUseLiterals from query to configuration.
Concerning the usage of Querydsl expressions the usage of code generation like documented here is advised http://www.querydsl.com/static/querydsl/3.3.1/reference/html/ch02s03.html
It will make your code typesafe, compact and readable.
If you want to try Querydsl without code generation you can replace
Path<Object> userPath = new PathImpl<Object>(Object.class, variable);
with
Path<Object> userPath = new RelationalPathBase<Object>(Object.class, variable, schema, table);
When working with QueryDSL, you must provide a template for the database platform to build the query for. I see you are already are doing this here:
private SQLTemplates templates = new MySQLTemplates();
private Configuration configuration = new Configuration(templates);
To make the schema name appear in the generated query, the only way I have found to do this is (there may be an easier way) is to extend the template class and explicitly call this.setPrintSchema(true); inside the constructor. Here is a class that should work for MySql:
import com.mysema.query.sql.MySQLTemplates;
public class NewMySqlTemplates extends MySQLTemplates {
public NewMySqlTemplates() {
super('\\', false);
}
public NewMySqlTemplates(boolean quote) {
super('\\', quote);
}
public NewMySqlTemplates(char escape, boolean quote) {
super(escape, quote);
this.setPrintSchema(true);
}
}
Then simply use this NewMySqlTemplates class in place of the MySQLTemplates class like this:
private SQLTemplates templates = new NewMySQLTemplates();
private Configuration configuration = new Configuration(templates);
I have this working using PostgresTemplates, so I may have a typo or mistake in the NewMySqlTemplates class above, but you should be able to get it to work. Good luck!
I am using Apache Jackrabbit as a database.
In my case, root node has numbers of child nodes(only at depth 1).
All child node has unique name, i.e., some Integer.
Each child Node have some properties that I have used further.
My task
I have to take top 10 nodes whose keys(integer values) are minimum.
My thinking
To achieve above goal, I make a query that sorts the keys of all child nodes, and pick top 10. Then by using that keys, I get all corresponding nodes, and after working, delete all that key/value pairs.
For that I searched a lot on the internet how to run the query. Can you please tell me how to run query on apache jackrabit. It is good, if you explain with example.
Edit no. 1
public class JackRabbit {
public static void main(String[] args) throws Exception {
try {
Repository repository = JcrUtils.getRepository("http://localhost:4502/crx/server");
javax.jcr.Session session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
Node root = session.getRootNode();
// Obtain the query manager for the session via the workspace ...
javax.jcr.query.QueryManager queryManager = session.getWorkspace().getQueryManager();
// Create a query object ...
String expression = "select * from nt:base where name= '12345' ";
javax.jcr.query.Query query = queryManager.createQuery(expression, javax.jcr.query.Query.JCR_SQL2);
// Execute the query and get the results ...
javax.jcr.query.QueryResult result = query.execute();
session.logout();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Exception
javax.jcr.query.InvalidQueryException: Query:
select * from nt:(*)base where name= '12345'; expected: <end>
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
at org.apache.jackrabbit.spi2dav.ExceptionConverter.generate(ExceptionConverter.java:69)
at org.apache.jackrabbit.spi2dav.ExceptionConverter.generate(ExceptionConverter.java:51)
at org.apache.jackrabbit.spi2dav.ExceptionConverter.generate(ExceptionConverter.java:45)
at org.apache.jackrabbit.spi2dav.RepositoryServiceImpl.executeQuery(RepositoryServiceImpl.java:2004)
at org.apache.jackrabbit.jcr2spi.WorkspaceManager.executeQuery(WorkspaceManager.java:349)
at org.apache.jackrabbit.jcr2spi.query.QueryImpl.execute(QueryImpl.java:149)
at jackrabbit.JackRabbit.main(JackRabbit.java:36)
I want to write a query of below scenereo
Here nodes having integer value have some properties. I want to sort these nodes by their integer values, and extract top 50 nodes for further processing.
Help me in that.
You should quote your node type name in JCR-SQL2:
select * from [nt:base]
This is one of the main differences between JCR-SQL and JCR-SQL2. Besides, name is a dynamic operand taking a selector argument. So a better way to write your query would be this:
select * from [nt:base] as b where name(b) = '12345'
You have different ways of executing your queries depending on the query language you want to use.
Take a look at this code for some simple query using only the API and not SQL like string queries.
You can take a look at JBoss Modeshape documentation for examples too since it is another JCR 2.0 implementation.
I hope this will help you to execute the query:
public FolderListReturn listFolder(String parentNode, String userid,String password) {
System.out.println("getting folders and files from = "+parentNode+" of user : "+userid);
SessionWrapper sessions =JcrRepositoryUtils.login(userid, password);
Session jcrsession = sessions.getSession();
Assert.notNull(name);
FolderListReturn folderList1 = new FolderListReturn();
ArrayOfFolders folders = new ArrayOfFolders();
try {
javax.jcr.query.QueryManager queryManager;
queryManager = jcrsession.getWorkspace().getQueryManager();
String expression = "select * from [nt:folder] AS s WHERE ISCHILDNODE(s,'"+name+"')and CONTAINS(s.[edms:owner],'*"+userid+"*') ORDER BY s.["+Config.EDMS_Sorting_Parameter+"] ASC";
javax.jcr.query.Query query = queryManager.createQuery(expression, javax.jcr.query.Query.JCR_SQL2);
javax.jcr.query.QueryResult result = query.execute();
for (NodeIterator nit = result.getNodes(); nit.hasNext();) {
Node node = nit.nextNode();
Folder folder = new Folder();
folder=setProperties(node,folder,userid,password,jcrsession,name);
folders.getFolderList().add(folder);
}
folderList1.setFolderListResult(folders);
folderList1.setSuccess(true);
} catch (Exception e) {
e.printStackTrace();
}finally{
//JcrRepositoryUtils.logout(sessionId);
}
return folderList1;
}