当前位置: 首页 > 知识库问答 >
问题:

如何使用查询DSL处理mysql json列?

壤驷坚
2023-03-14

想知道如何看待mysql json专栏?

product table:
...
    category_ids                     json                         null,
...

category_ids例如) [19, 102, 108]

如果我想搜索包含类别id 102的产品列表,如何使用queryDSL进行查询?

我尝试了JsonNode类型,但它不起作用。

共有1个答案

羊舌青青
2023-03-14

根据这些标记,我假设您使用查询列表创建 JPQL(或Hibernate HQL)查询。这一点很重要,因为为了让JSON类型与查询一起使用,它们不仅必须使用查询和MySQL,而且最重要的是使用查询语言本身,在这种情况下来自Hibernate。

我假设您已经成功地将json列正确地映射到JacksonsJsonNode类型。如果没有,那么重要的是要注意,对于任何非标准类型,都需要在Hibernate中注册自定义类型。您可以制作自己的自定义类型,也可以使用现有的实现。我强烈推荐Vlad开发hibernate-type库(包括我自己在内的一些人的贡献)。如何将hibernate-type集成到您的项目中,在他对Stackoverflow问题的回答中得到了很好的解释:https://stackoverflow.com/a/37946530/2104280

您需要做的第一件事是在项目pom中设置以下Hibernate Types Maven依赖项。xml配置文件:

   <dependency>
       <groupId>com.vladmihalcea</groupId>
       <artifactId>hibernate-types-52</artifactId>
       <version>${hibernate-types.version}</version>
   </dependency>

现在,您需要在类级别或package-info.java包级别描述符中声明JsonType,如下所示:

   @TypeDef(name = "json", typeClass = JsonType.class)

并且,实体映射将如下所示:

   @Type(type = "json")
   @Column(columnDefinition = "jsonb")
   private Location location;

现在,您将能够在查询中的简单操作中使用 JSON 属性。允许的操作基本上包括基本比较(=!=IS(非)空)。其他操作不可用,因为这些操作仅在 MySQL 中定义,而不是在 JPQL 或 HQL 查询语言中定义。

您要检查 JSON 数组是否包含特定元素。我假设category_ids表示一个 JSON 数组。那么这意味着你想要生成的MySQL代码段很可能是category_ids? :类别Id

我想指出的是,这仅适用于存储为字符串的ID,而不是JSON数组中的数字。您可能希望将category_ids映射为双关语[]。与 JSON 类型一样,Hibernate类型库也支持数组类型,因此答案对于数组的工作方式相同。

但是,JSON_CONTAINS(category_ids,:categoryId)不是有效的HQL/JPQL,因为该查询语言中不存在该函数。如果我们想在HQL/JPQL中呈现JSON_CONTAINS(category_ids,:categoryId),我们需要定义一个自定义函数,将JSON_CCONTAINS。

有两种方法可以在Hibernate中声明自定义函数。

  1. 扩展您正在使用的方言,并在那里声明函数。https://stackoverflow.com/a/42486291/2104280 中很好地描述了这种方法。
  2. 使用元数据生成器初始化程序 SPI 在引导期间注册自定义函数。https://stackoverflow.com/a/41369853/2104280 中介绍了此方法。

使用< code > MetadataBuilderInitializer 方法,代码将如下所示:

public class JSONMetadataBuilderInitializer
        implements MetadataBuilderInitializer {
    @Override
    public void contribute(MetadataBuilder metadataBuilder,
            StandardServiceRegistry serviceRegistry) {
        metadataBuilder.applySqlFunction("json_contains_key",
            new SQLFunctionTemplate(BooleanType.INSTANCE,
                "JSON_CONTAINS(?1, ?2, '$'"));
    }
}

最后,您最终会为您的JsonNode属性获得一个Hibernate类型,以及一个用于检查是否存在密钥的自定义函数。密钥可以在JPQL/HQL中如下使用:

SELECT product FROM Product product WHERE json_contains_key(product.categories, '1234') = true;

这将产生以下 SQL:

SELECT * FROM product WHERE JSON_CONTAINS(categories, '1234', '$') = true;

然而,您希望通过Querydsl构建这个JPQL/HQL查询,这意味着还需要几个步骤。我们需要为创建的函数构造新的表达式类型。基本上有两种选择:

  1. 创建一个新的运算符实现,并在扩展的 JPQL 模板中为该运算符注册一个模板
  2. 创建一个模板表达式(字面意思是 JPQL 的片段)。

第二种方法更简单,所以我将在这里使用。使用TemplateExpression,Querydsl中的以下代码将生成上述JPQL查询:

queryFactory.select(QProduct.product)
    .from(QProduct.product)
    .where(Expressions.booleanTemplate(
        "json_contains_key({0}, {1})",
        QProduct.product.categories,
        Expressions.constants("1234").isTrue())
    .fetch();

然而,这并不像您在Querydsl中习惯的那样流畅。可以使用自定义表达式类型扩展Querydsl,并在此假设引入JsonExpression。还可以扩展querydsl apt,以便在静态元模型(Q-classes)中自动生成此表达式类型的路径。我专门为此构建了扩展库hibernate types querydsl apt。它为Hibernate types项目中的自定义类型添加了各种自定义表达式类型(例如范围、数组、json、hstore、间隔)。它还自动注册主操作的自定义函数。使用我的扩展,数组的用例将非常简单:

@Entity
@TypeDefs({
        @TypeDef(name = "int-array", typeClass = IntArrayType.class, defaultForType = int[].class)
})
public class ArrayEntity {
    @Id
    Long id;

    @Type(type = "int-array")
    @Column(name = "sensor_values", columnDefinition = "integer[]")
    int[] sensorValues;
}
List<Tuple> fetch = new JPAQuery<>(entityManager, ExtendedHQLTemplates.DEFAULT)
    .from(arrayEntity)
    .select(arrayEntity)
    .where(arrayEntity.sensorValues.contains(123))
    .fetch();

更多示例请访问:https://github.com/jwgmeligmeyling/hibernate-types-querydsl-apt/blob/master/querydsl-ext-testsuite/src/test/java/com/pallasathenagroup/querydsl/ArrayEntityPathTest.java .

 类似资料:
  • 样本子句 sample_clause允许您指示数据库从表中的随机数据样本中进行选择,而不是从整个表中进行选择。 我想使用QueryDSL运行下面的查询 样本子句 sample_clause允许您指示数据库从表中的随机数据样本中进行选择,而不是从整个表中进行选择。 从测试t样本(80)中选择,其中t.test_id=01,t.test _ suite _ id = 02 其中条件是动态的,我使用qu

  • 问题内容: 我有以下查询: 查询在具有25.000行的数据库表上执行。该查询的执行时间约为40秒。结果将显示在网页上,因此等待40秒以获取结果并不是很好。 有没有一种方法可以执行此查询并保存其输出?因为如果每天晚上执行此查询就足够了。 最好的方法是什么?我应该创建一个cronjob并执行此查询并将结果写入数据库吗?或者,还有更好的方法? 或者我可以优化此查询以使其更快? 问题答案: 我认为所有这些

  • 需要实现sql查询,如: 如何使用QueryDSL编写这样的语句?(我没有使用任何JPA)。任何帮助/提示都非常感谢!

  • 主要内容:匹配所有查询,全文查询,匹配查询,multi_match查询,查询字符串查询,期限等级查询,范围查询,复合查询,连接查询,地理查询在Elasticsearch中,通过使用基于JSON的查询进行搜索。 查询由两个子句组成 - 叶查询子句 - 这些子句是匹配,项或范围的,它们在特定字段中查找特定值。 复合查询子句 - 这些查询是叶查询子句和其他复合查询的组合,用于提取所需的信息。 Elasticsearch支持大量查询。 查询从查询关键字开始,然后以对象的形式在其中包含条件和过滤器。以下描

  • 问题内容: 我是事件/回调样式编程和NodeJS的新手。我正在尝试实现一个小的http服务器,它使用node-mysql模块来提供ddbb数据。 我的问题来自查询结构。由于经常有一些查询需要运行先前查询的结果,因此我无法同时(异步)运行所有查询,因此不得不等待一些结果。 我的第一种方法是同时运行所有非依赖性查询,然后循环运行,直到所有非依赖性查询都设置了一个标志,说我已经完成,这样我就可以继续处理