概述
Postgres 和 Oracle 广泛支持存储在数据库中的 JSON。两者都为使用文档路径表达式编写查询提供了大量支持。
Ebean 通过 @DbJson
和 @DbJsonB
提供映射支持,以将 JSON 文档映射到各种数据库类型,包括 Postgres JSON、JSONB 类型以及标准 Varchar、Clob 和 Blob 类型。该映射可与所有受支持的数据库一起使用,而 Postgres 和 Oracle 支持在查询 where 子句中包含 JSON 表达式。
Postgres 和 Oracle 都支持使用 JSON 表达式编写查询,而 Ebean 公开了最常见的查询表达式。
映射
对于所有数据库,JSON 文档都可以映射到实体 Bean,并可以从数据库中保存和加载。
@DbJsonB
在实体 Bean 中,可以使用 @DbJsonB
对属性进行注释,这表示该属性映射到 JSONB 数据库类型。对于非 Postgres 数据库,这映射到数据库 Clob。
@Entity
@Table(name="p_doc")
public class SimpleDoc extends Model {
@Id
Long id;
...
@DbJsonB
Map<String,Object> content;
// Ordinary bean - use Jackson object mapper
@DbJsonB
PlainBean plainBean;
@DbJson
在实体 Bean 中,可以使用 @DbJson
对属性进行注释,这表示该属性映射到 JSON 数据库类型。对于非 Postgres 数据库,这映射到数据库 Clob。
@Entity
@Table(name="p_doc")
public class SimpleDoc extends Model {
@Id
Long id;
...
@DbJson
Map<String,Object> content;
// Ordinary bean - use Jackson object mapper
@DbJson
PlainBean plainBean;
保存和查找
将 JSON 内容放入内容属性并保存,然后像往常一样获取。
String rawJson = "{\"docName\":\"My document\", \"docScore\":234, \"title\":\"Some title\"}";
// get the JSON into a map using Jackson or similar tool.
// Ebean has EJson which using Jackson core which can be used
// to parse JSON content
Map<String, Object> content = EJson.parseObject(rawJson);
SimpleDoc doc = new SimpleDoc();
doc.setName("doc1");
doc.setContent(content);
// save to db
doc.save();
// fetch from db
SimpleDoc doc1 = SimpleDoc.find.byId(doc.getId());
assertEquals("My document", doc1.getContent().get("docName"));
查询表达式
Postgres
和 Oracle
提供表达式,以便可以使用 path
表达式来测试给定的路径 EXISTS
或测试路径中的值。
Ebean ExpressionList
具有以下表达式的表达式
/**
* Path exists - for the given path in a JSON document.
*/
ExpressionList<T> jsonExists(String propertyName, String path);
/**
* Path does not exist - for the given path in a JSON document.
*/
ExpressionList<T> jsonNotExists(String propertyName, String path);
/**
* Equal to expression for the value at the given path in the JSON document.
*/
ExpressionList<T> jsonEqualTo(String propertyName, String path, Object value);
/**
* Not Equal to - for the given path in a JSON document.
*/
ExpressionList<T> jsonNotEqualTo(String propertyName, String path, Object val);
/**
* Greater than - for the given path in a JSON document.
*/
ExpressionList<T> jsonGreaterThan(String propertyName, String path, Object val);
/**
* Greater than or equal to - for the given path in a JSON document.
*/
ExpressionList<T> jsonGreaterOrEqual(String propertyName, String path, Object val);
/**
* Less than - for the given path in a JSON document.
*/
ExpressionList<T> jsonLessThan(String propertyName, String path, Object val);
/**
* Less than or equal to - for the given path in a JSON document.
*/
ExpressionList<T> jsonLessOrEqualTo(String propertyName, String path, Object val);
Postgres 表达式
Ebean 使用 Postgres ->>
和 #>>
运算符来支持 JSON 表达式。
Exists 表达式
对于 Postgres Ebean 的 jsonExists()
jsonNotExists()
表达式,路径值使用 ->>
或 #>>
和 IS NULL
和 IS NOT NULL
。
List<SimpleDoc> list = new QSimpleDoc().query()
.where()
.jsonExists("content", "path.other")
.findList();
该函数可用于 Ebean 查询中,如下所示
select t0.id c0, ...
where (t0.content #>> '{path,other}') is not null
值表达式
对于 Postgres,Ebean 的值表达式(例如 jsonEqualTo()
、jsonGreaterThan()
等)根据路径使用 ->>
或 #>>
运算符,然后根据要测试的值转换结果。也就是说,如果要测试的值是 Integer 或 Long,则 DB 路径表达式将转换为 ::INTEGER
,并且 ::DECIMAL
和 ::BOOLEAN
也存在类似的转换。
List<SimpleDoc> list = new QSimpleDoc().query()
.where()
.jsonEqualTo("content", "path.other", 34)
.findList();
select t0.id c0, ...
where (t0.content #>> '{path,other}')::INTEGER = ?
Oracle 表达式
Ebean 使用 Oracle 的 json_exists
和 json_value
函数来支持 Ebean 的 JSON 表达式。
Exists 表达式
对于 Oracle,Ebean 的 jsonExists() 表达式使用 Oracle json_exists
函数。
List<SimpleDoc> list = new QSimpleDoc().query()
.where()
.jsonExists("content", "path.other")
.findList();
该函数可用于 Ebean 查询中,如下所示
select t0.id c0, ...
where json_exists(t0.content, '$.path.other')
值表达式
对于 Oracle,Ebean 的值 jsonEqualTo() jsonGreaterThan() 等使用 Oracle json_value
函数。
List<SimpleDoc> list = new QSimpleDoc().query()
.where()
.jsonEqualTo("content", "path.other", 34)
.findList();
select t0.id c0, ...
where json_value(t0.content, '$.path.other') = ?
原始表达式
如果提供的表达式与要求不符,则可以使用 raw()
表达式。
List<SimpleDoc> docs = SimpleDoc.find.where()
// pass a raw expression through - property names are translated to
// db columns but everything else is passed through to the DB
.raw("content#>'{docName}' ? 'rob doc'")
.findList();