I am facing issues while retrieving/searching through Postgres JSONB column using CriteriaBuilder.
Postgres Query : SELECT * FROM table where lower(jsonb_extract_path(tags,'Case')::text) = lower('"normal"') as text));
Tags: datatype of tags column is JSONB.
Above query is working fine using postgres client.
But I was facing issues while trying to get it done from CriteriaBuilder.
Following is my code:
private Specification<TemplateMetadata> findByTagsFilter(Map<String, String[]> requestParameterMap) {
return (root, query, builder) -> {
List<Predicate> predicates = new ArrayList<>();
if (!StringUtils.isEmpty(requestParameterMap)) {
predicates = requestParameterMap.entrySet().stream()
.filter(keyValue1 -> validateKeyValues(keyValue1.getKey()))
.map(keyValue2 -> Arrays.asList(keyValue2.getValue()).stream()
.map(v -> builder.equal(builder.function("jsonb_extract_path", String.class, builder.lower(root.<String>get("tags")), builder.literal(keyValue2.getKey())) , builder.lower(builder.literal("\""+v+"\"")).as(JsonDataType.class)))
.flatMap(list -> list.distinct())
.collect(Collectors.toList());
}
return builder.and(
predicates.toArray(new Predicate[predicates.size()])
);
};
}
requestParameterMap is filled by REST (API URI should looks like : ?testtag1=testtag1&testtag2=testtag2)
I am getting follwoing Error
ERROR: function lower(jsonb) does not exist\n Hint: No function matches the given name and argument types. You might need to add explicit type casts.\n Position: 444
Can some one help me on this.
I'm trying to create an sql sentence using querydsl. What I'm trying to get is:
SELECT P.KEY, COUNT(P.VALUE)
FROM RESOURCES R JOIN PROPERTIES P ON R.ID = P.ID
WHERE P.KEY = "key" AND p.VALUE = "value"
GROUP BY P.VALUE;
I've tried to write some querydsl code:
String s = queryFactory
.query()
.from(QResource.resource)
.join(QProperty.property)
.where(QResource.resource.properties.any().key.eq("key").and(QResource.resource.properties.any().value.eq("value")))
.groupBy(QProperty.property.value)
.select(QProperty.property.key, QProperty.property.value.count())
.toString();
I'm guessing it can be simplified and by other hand I don't quite see if it's well querydsl-coded.
Any ideas?
A more simplified version would be:
QResource r = QResource.resource;
QProperty p = QProperty.property;
queryFactory
.select(p.key, p.value.count())
.from(r)
.join(p).on(r.id.eq(p.id))
.where(p.key.eq("key"), p.value.eq("value"))
.groupBy(p.value)
.fetchOne();
Adding to #natros answer, Boolean operators can be used for 'and' logic
QResource r = QResource.resource;
QProperty p = QProperty.property;
queryFactory
.select(p.key, p.value.count())
.from(r)
.join(p).on(r.id.eq(p.id))
.where(p.key.eq("key").and(p.value.eq("value")))
.groupBy(p.value)
.fetchOne();
Boolean builders can be also used for complex logics
BooleanBuilder builder = new BooleanBuilder();
builder.and(p.key.eq("key"));
builder.and(p.value.eq("value"));
queryFactory
.select(p.key, p.value.count())
.from(r)
.join(p).on(r.id.eq(p.id))
.where(builder)
.groupBy(p.value)
.fetchOne();
I am new to doctrine2(PHP) which is inspired from hibernate(java). I have searched at many places by didn't get appropriate answer.
what is the use of following code of line, what will happen if I do not use it?
$em->getConnection()->close();
For example If I have made following method in my class :
public static function deleteWish( $about_ilook_user_id, $link_ilook_user_id, $flush_automatic = TRUE )
{
$em = \Zend_Registry::get('em');
$new_link_wishes_objs = $em->getRepository( '\Entities\new_link_wishes' )->findBy( array( 'ilookUser' => $about_ilook_user_id, 'link_ilook_user_id' => $link_ilook_user_id ) );
foreach ( $new_link_wishes_objs as $new_link_wishes_obj )
{
$em -> remove($new_link_wishes_obj);
}
$em -> flush();
$em->getConnection()->close();
}
Should I call getConnection()->close(); on $em(entity manager).
I have a feeling I'm going about this all wrong. But anyway.
I have an sql database which has essentially a purposefully denormalised table which I've constructed to make this task easier for me, so I can just grab stuff from one table.
What I have is a table of pairs, something like this:
user_lo | user_hi | something_else | other stuff
1000 | 1234 | 1231251654 | 123
1050 | 1100 | 1564654 | 45648
1080 | 1234 | 456444894648 | 1
And so on.
So for my neo4j graph db, I want each user id as a node, the other stuff isn't too important but will be the stuff in the relations basically.
I only want one node for each user, so my feeling is that if I do something like this:
while (rs.next()) {
node_lo = db.createNode();
node_lo.setProperty("user_id", rs.getInt(1));
node_hi = db.createNode();
node_hi.setProperty("user_id", rs.getInt(2));
}
That when we add the node with user_id 1234 for the second time, it will just create a new node, but I what I want is for it to just grab this node instead of creating it so I can add it to the relationship to 1080 in this case.
So what is the way to do this?
Have you looked at CREATE UNIQUE?
If you can't use Cypher, maybe you can use unique nodes?
Use an index to search, and if no result of found, create a new one.
Index<Node> userIndex = graphDatabaseService.index().forNodes('UserNodes');
IndexHits<Node> userNodes = userIndex.get('id', 1234);
if(!userNodes.hasNext()){
//Create new User node
} else {
Node userNode = userNodes.next();
}
Is this the type of operation you are looking for?
You'll probably want to use the UniqueNodeFactory provided by Neo4j.
public Node getOrCreateUserWithUniqueFactory( String username, GraphDatabaseService graphDb )
{
UniqueFactory<Node> factory = new UniqueFactory.UniqueNodeFactory( graphDb, "UserNodes" )
{
#Override
protected void initialize( Node created, Map<String, Object> properties )
{
created.setProperty( "id", properties.get( "id" ) );
}
};
return factory.getOrCreate( "id", id );
}
Normalize your SQL tables to look like nodes and relationships. Then with cypher in your migration you can make the migration rerunnable by something like
start a = node:node_auto_index('id:"<PK_Value>"')
delete a
create a = {id: "<PK_VALUE>", etc}
for nodes and since you should have in your many-to-many middle table:
start LHS = node:node_auto_index('id:"<LHS_PK>"'),
RHS = node:node_auto_index('id:"<RHS_PK>"')
create unique LHS=[:<relType> {<rel props>}]->RHS
now you will end up with no duplicates and can rerun as much as you like.
use this function:
where:
ID is the key which you want to check if already exist
Type: is the type of the node ( the label)
this function will create the node and return it, then you can add more properties.
public static Node getOrCreateUserWithUniqueFactory( long ID, GraphDatabaseService graphDb, String Type )
{
UniqueFactory<Node> factory = new UniqueFactory.UniqueNodeFactory( graphDb, Type )
{
#Override
protected void initialize( Node created, Map<String, Object> properties )
{
created.addLabel( DynamicLabel.label( Type ) );
created.setProperty( "ID", properties.get( "ID" ) );
}
};
return factory.getOrCreate( "ID", ID );
}
using cypher query, you can create a unique node with the following syntax,
CYPHER 2.0 merge (x:node_auto_index{id:1})
when making a REST call, one can make batch insertion like
$lsNodes[] = array(
'method'=> 'POST', 'to'=> '/cypher',
'body' => array(
'query' => 'CYPHER 2.0 merge (x:node_auto_index{id_item:{id}})',
'params' => array('id'=>1)
),
'id'=>0
);
$sData = json_encode($lsNodes);
similarly for creating relationships in a batch request, do the following
$lsNodes[] = array(
'method'=> 'POST', 'to'=> '/cypher',
'body' => array(
'query' => 'start a=node:node_auto_index(id={id1}), b = node:node_auto_index(id={id2}) create unique a-[:have{property:30}}]-b;',
'params' => array(
'id1' => 1, 'id2'=> 2
)
),
'id' => 0
);
$sData = json_encode($lsNodes);
I'm trying to use sun-codemodel to generate source code, checking the API for a long time however no luck.
JBlock body2 = method2.body();
JInvocation arg = body2.invoke( "a" ).arg( xxx ).invoke( "c" ).arg( xxx );
only generate the first part, i.e. a(xxx)
Any ideas?
Problem solved by using
JInvocation invoke = JExpr._this()
.invoke( "fun" )
.arg( "arg1" )
.invoke( "fun2" )
.arg( "arg2" );
method.body().add(invoke);