Search code examples
javaspring-bootspring-data-jpaquerydsl

Filter for Key-Value pairs using Querydsl


My issue needs a bit of explanation. I try to keep it as short possible without missing important aspects. So already thanks to everyone who reads this through until the end.

What I try to achieve

perform a GET request with several query parameters as filters

api/parentResource?areaCode=11&childEntity.kvlist.API_KEY=123CBA321

The example request will retrieve a list of parentResource that belong to a certain area AND have the key-value pair API_KEY=123CBA321 in their child entity's list (the list itself is also a child entity of the child entity, for brevity let's call it KV_list).

Using Querydsl I got this working so far, but there is one thing I couldn't solve myself:

The issue is that querydsl probably behaves as expected 1 when using AND conjunctions. What I need to achieve is, that the filter on KV_list only returns a truthy BooleanExpression/Predicate if the actual KV-pair exists.

Example:

KV_list table contains following records:

+-------+-----------+-----------+---------------+
|  id   |    key    |   value   |  foreign_key  |
+-------+-----------+-----------+---------------+
| UUID1 | API_KEY   | 123CBA321 | childEntityFK |
| UUID2 | KEY2      | XYZ987    | childEntityFK |
| UUID3 | OTHER_KEY | NNN       | childEntityFK |
+-------+-----------+-----------+---------------+

While you would expect the GET request from above to work, the following shouldn't return anything, as the KV-pair doesn't exist:

api/parentResource?areaCode=11&childEntity.kvlist.KEY2=NNN

1 unfortunately, querydsl simply checks if there is a key=KEY2 AND a value=NNN and then returns a truthy predicate.

The model looks like: Parent <--1:n--> ChildEntity <--1:n--> KV_Entity

What I tried so far

  • simple conjunction of key and value:

     ExpressionUtils.allOf(this.predicate,
     QParent.parent.childEntities.any().kvEntities.any().key.eq(var_key),
     QParent.parent.childEntities.any().kvEntities.any().value.eq(var_value)
     );
    
  • directly call eq method on KV-object:

    ExpressionUtils.and(this.predicate,
    QParent.parent.childEntities.any().kvEntities.any()eq(var_kvObject)
    );
    
  • JPAExpressions.select().from().join()...

  • several flavours of the approaches mentioned above

I'm really stuck and would appreciate any help/hints. Thanks in advance!


frameworks/libraries being used:

  • Spring Boot 2.0.4
  • Querydsl 4.1.4


Solution

  • I dont know the full context of your question. Maybe you can create a virtual key (Hash).

    That contains var_key and var_value.

    Then you can use QParent.parent.childEntities.any().kvEntities.any().hash.eq(hash) To search for kvEntities