我正在做一个项目,我有一个 java 服务与存储 json 对象的数据库对话。 json 对象称为
scanResultCollection
。它有一个名为organization
的顶级属性。当以独立模式(即 - 在我的工作站上)运行时,我已经设置了它使用 sqlite 的地方。部署后它会自动切换到 postgres。
这里是相关的一段代码:
EntityManager entityManager = ctx.attribute(App.RESULT_TABLE_ENTITY_MANAGER);
var criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Result> criteriaQuery = criteriaBuilder.createQuery(Result.class);
Root<Result> root = criteriaQuery.from(Result.class);
var organizationPath = JPathHelpers.getJsonPathFor(
List.of(ScanResultCollection.ORGANIZATION_KEY)
);
LOG.info("organizationPath is: {}", organizationPath);
var predicate = criteriaBuilder.equal(
criteriaBuilder.function(
"jsonb_extract_path_text",
//"json_extract", // @TODO this should be a config value as it's db specific
String.class,
// TODO see note in Result entity for why we're not using the generated metamodel for now
// TODO when looking into the ScanResultCollection json object
root.get(SCAN_RESULT_COLLECTION_ATTRIBUTE),
//criteriaBuilder.literal(organizationPath)
criteriaBuilder.literal("organization")
),
org
);
criteriaQuery.select(root).where(predicate);
var query = entityManager.createQuery(criteriaQuery);
List<Result> results = query.getResultList();
基本上发生的事情是调用者为
organization
提供了一个值,我们正在努力查询数据库以查找具有与调用者提供的值匹配的 scanResultCollection
值的所有 organization
对象。
对于 sqlite,函数
json_extract
正在被使用,并且 organizationPath
的值解析为 $.organization
。所有这些都很完美。
对于 postgres,我们需要将函数名称更改为
jsonb_extract_path_text
- 没问题,因为显然 postgres 是与 sqlite 不同的数据库系统。让我难过一整天的是 "$.organizationPath"
不起作用并且总是返回零结果。为了让 postgres 执行与 sqlite 相同的工作,有必要提供字符串 "organization"
而不是 jsonpath 形式 "$.organization"
.
docs 声明参数是 JSONPath 类型,最终我发现对于 Postgres
JSONPath
的含义与它在我所知道的几乎任何其他用例中的含义不同 - 特别是在 $
的含义方面.
$
字符。这是我的问题
"$.organization"
在 sqlite 和 postgres 上下文中都不起作用?看起来在 Postgres 中(实际上在 Oracle 和 SqlServer 中)$
是 “表示正在查询的 JSON 值的变量(上下文项)”。 “上下文项”不是“当前项”吗?在这种情况下,它类似于根 JSON 元素?归根结底,令我感到奇怪的是,主要的 SQL 数据库供应商会以一种与世界其他地方使用它的方式不兼容的方式实现像 JSONPath 这样常见的事实上标准化的东西——这告诉我我可能遗漏了一些东西,如果是的话我很好奇那东西可能是什么......
提前!