如何使用环回 REST API 过滤器查询 MySQL JSON 字段值
How to Query MySQL JSON Field Values with a Loopback REST API Filter
在 MySQL (5.7) JSON 字段中查询值的正确环回过滤器格式是什么?例如,我们如何使用环回 REST 过滤器执行此查询?
查询
SELECT name, info->"$.id", info->"$.team"
FROM employee
WHERE JSON_EXTRACT(info, "$.team") = "A"
ORDER BY info->"$.id";
示例数据
+---------------------------+----------
| info | name
+---------------------------+---------
| {"id": "1", "team": "A"} | "Sam"
| {"id": "2", "team": "A"} | "Julie"
| {"id": "3", "name": "B"} | "Rob"
| {"id": "4", "name": "B"} | "Cindy"
+---------------------------+---------
尝试失败
/employee?filter[where][info->$.team]=A
/employee?filter[where][info.team]=A
/employee?filter[where][info][team]=A
我认为目前这不可能,我认为连接器都不支持 JSON_EXTRACT。
https://github.com/strongloop/loopback-connector-mysql
我认为要执行此类查询,您可以使用原始查询并使用实际连接器编写自定义代码。
由于这个问题是第一个从 Google 搜索中弹出的问题,而且环回 mysql 连接器仍然不允许 json 查询,我觉得应该有一个正确的答案提供给未来的读者。
解决方法是自己直接在连接器上添加功能,直到环回策略决定如何真正处理它。
我们的做法是:将其放入您的 /connectors
文件夹中:
import * as connector from "loopback-connector-mysql"
var g = require('strong-globalize')();
var SqlConnector = require('loopback-connector').SqlConnector;
var ParameterizedSQL = SqlConnector.ParameterizedSQL;
const _buildExpression = connector.MySQL.prototype.buildExpression;
connector.MySQL.prototype.buildExpression = function (columnName, operator, operatorValue, propertyDefinition) {
if (operator === 'json') {
operatorValue = JSON.parse(operatorValue);
const keys = Object.keys(operatorValue);
if (keys.length > 1) {
g.warn('{{MySQL}} {{json}} syntax can only receive one key, received ' + keys.length);
}
const jsonPointer = "$." + keys[0];
const value = operatorValue[keys[0]];
const column = `JSON_EXTRACT(${columnName}, "${jsonPointer}")`;
if (value && value.constructor === Object) {
// this includes another operator, apply it on the built column
const operator = Object.keys(value)[0];
return _buildExpression.apply(this, [column, operator, value[operator], propertyDefinition]);
}
const clause = `${column} = ?`;
return new ParameterizedSQL(clause,
[value]);
} else {
return _buildExpression.apply(this, [columnName, operator, operatorValue, propertyDefinition])
}
};
export default connector;
然后在您的数据库配置 connector: 'connectors/mysql-json'
中指向此文件,如果不起作用,则将其要求连接到连接器中(文档说我们可以定义一个路径,但我们无法让它工作...)
这很简单,我们重写 buildExpression
函数以便能够插入一个新的运算符 json
。这将使它可以在您使用其他运算符的任何地方使用,例如 gt
、lt
、nin
等
我们更进一步,允许在您的 json 运算符中传递运算符,以便也能够利用它们。
这是一个示例查询过滤器:
{"where":
{
"jsonProperty":{"json":{"id":1}}
}
}
// Results in
// WHERE JSON_EXTRACT('jsonProperty', '$.id') = 1
{"where":
{
"jsonProperty":{"json":{"id":{"gt":1}}}
}
}
// Results in
// WHERE JSON_EXTRACT(`jsonProperty`, '$.id') > 1
我们只是在传递给 json
的对象的键前面加上 $.
以便于使用(不确定它是否最好,但对我们有用)。您可以将任何 json 路径写为键,只需省略 $.
在 MySQL (5.7) JSON 字段中查询值的正确环回过滤器格式是什么?例如,我们如何使用环回 REST 过滤器执行此查询?
查询
SELECT name, info->"$.id", info->"$.team"
FROM employee
WHERE JSON_EXTRACT(info, "$.team") = "A"
ORDER BY info->"$.id";
示例数据
+---------------------------+----------
| info | name
+---------------------------+---------
| {"id": "1", "team": "A"} | "Sam"
| {"id": "2", "team": "A"} | "Julie"
| {"id": "3", "name": "B"} | "Rob"
| {"id": "4", "name": "B"} | "Cindy"
+---------------------------+---------
尝试失败
/employee?filter[where][info->$.team]=A
/employee?filter[where][info.team]=A
/employee?filter[where][info][team]=A
我认为目前这不可能,我认为连接器都不支持 JSON_EXTRACT。
https://github.com/strongloop/loopback-connector-mysql
我认为要执行此类查询,您可以使用原始查询并使用实际连接器编写自定义代码。
由于这个问题是第一个从 Google 搜索中弹出的问题,而且环回 mysql 连接器仍然不允许 json 查询,我觉得应该有一个正确的答案提供给未来的读者。
解决方法是自己直接在连接器上添加功能,直到环回策略决定如何真正处理它。
我们的做法是:将其放入您的 /connectors
文件夹中:
import * as connector from "loopback-connector-mysql"
var g = require('strong-globalize')();
var SqlConnector = require('loopback-connector').SqlConnector;
var ParameterizedSQL = SqlConnector.ParameterizedSQL;
const _buildExpression = connector.MySQL.prototype.buildExpression;
connector.MySQL.prototype.buildExpression = function (columnName, operator, operatorValue, propertyDefinition) {
if (operator === 'json') {
operatorValue = JSON.parse(operatorValue);
const keys = Object.keys(operatorValue);
if (keys.length > 1) {
g.warn('{{MySQL}} {{json}} syntax can only receive one key, received ' + keys.length);
}
const jsonPointer = "$." + keys[0];
const value = operatorValue[keys[0]];
const column = `JSON_EXTRACT(${columnName}, "${jsonPointer}")`;
if (value && value.constructor === Object) {
// this includes another operator, apply it on the built column
const operator = Object.keys(value)[0];
return _buildExpression.apply(this, [column, operator, value[operator], propertyDefinition]);
}
const clause = `${column} = ?`;
return new ParameterizedSQL(clause,
[value]);
} else {
return _buildExpression.apply(this, [columnName, operator, operatorValue, propertyDefinition])
}
};
export default connector;
然后在您的数据库配置 connector: 'connectors/mysql-json'
中指向此文件,如果不起作用,则将其要求连接到连接器中(文档说我们可以定义一个路径,但我们无法让它工作...)
这很简单,我们重写 buildExpression
函数以便能够插入一个新的运算符 json
。这将使它可以在您使用其他运算符的任何地方使用,例如 gt
、lt
、nin
等
我们更进一步,允许在您的 json 运算符中传递运算符,以便也能够利用它们。
这是一个示例查询过滤器:
{"where":
{
"jsonProperty":{"json":{"id":1}}
}
}
// Results in
// WHERE JSON_EXTRACT('jsonProperty', '$.id') = 1
{"where":
{
"jsonProperty":{"json":{"id":{"gt":1}}}
}
}
// Results in
// WHERE JSON_EXTRACT(`jsonProperty`, '$.id') > 1
我们只是在传递给 json
的对象的键前面加上 $.
以便于使用(不确定它是否最好,但对我们有用)。您可以将任何 json 路径写为键,只需省略 $.