BigQuery具有在实时交互式查询中解析JSON的功能:只需将JSON编码对象存储为字符串,并使用JSON_EXTRACT_SCALAR等函数实时查询。
但是,我无法找到发现这些对象中所有键(属性)的方法。
我可以使用UDF吗?
答案 0 :(得分:4)
以下版本修复了一些"问题"在原始答案中如下:
1.只发出第一级键
2.必须手动编译并运行最终查询以根据发现的密钥提取信息
SELECT type, key, value, COUNT(1) AS weight
FROM JS(
(SELECT json, type
FROM [fh-bigquery:openlibrary.ol_dump_20151231@0]
WHERE type = '/type/edition'
),
json, type, // Input columns
"[{name: 'type', type:'string'}, // Output schema
{name: 'key', type:'string'},
{name: 'value', type:'string'}]",
"function(r, emit) { // The function
x = JSON.parse(r.json);
processKey(x, '');
function processKey(node, parent) {
if (parent !== '') {parent += '.'};
Object.keys(node).map(function(key) {
value = node[key].toString();
if (value !== '[object Object]') {
emit({type:r.type, key:parent + key, value:value});
} else {
processKey(node[key], parent + key);
};
});
};
}"
)
GROUP EACH BY type, key, value
ORDER BY weight DESC
LIMIT 1000
结果如下
Row type key value weight
1 /type/edition type.key /type/edition 25140209
2 /type/edition last_modified.type /type/datetime 25140209
3 /type/edition created.type /type/datetime 17092292
4 /type/edition languages.0.key /languages/eng 14514830
5 /type/edition notes.type /type/text 11681480
6 /type/edition revision 2 8714084
7 /type/edition latest_revision 2 8704217
8 /type/edition revision 3 5041680
9 /type/edition latest_revision 3 5040634
10 /type/edition created.value 2008-04-01T03:28:50.625462 3579095
11 /type/edition revision 1 3396868
12 /type/edition physical_format Paperback 3181270
13 /type/edition revision 4 3053266
14 /type/edition latest_revision 4 3053197
15 /type/edition revision 5 2076094
16 /type/edition latest_revision 5 2076072
17 /type/edition publish_country nyu 1727347
18 /type/edition created.value 2008-04-30T09:38:13.731961 1681227
19 /type/edition publish_country enk 1627969
20 /type/edition publish_places London 1613755
21 /type/edition physical_format Hardcover 1495864
22 /type/edition publish_places New York 1467779
23 /type/edition revision 6 1437467
24 /type/edition latest_revision 6 1437463
25 /type/edition publish_country xxk 1407624
答案 1 :(得分:1)
如何在BigQuery中使用JavaScript UDF提取所有JSON对象键:
$('.ty-profile-field__select-state').val('');
$('.ty-profile-field__select-state option:first').prop('selected', true);
$('.ty-profile-field__select-state option').each(function() { $(this).prop('selected', false); });
$(".ty-profile-field__select-state option:first").prop('selected', true);
$('.ty-profile-field__select-state').find('option:selected').prop('selected', false);
enter code here
分组并计算:
一旦找到了可以使用的所有密钥,就可以在普通的SQL查询中使用JSON_EXTRACT_SCALAR:
现在您知道了密钥,您可以提取所有已知类型的信息:
SELECT type, key
FROM (
SELECT * FROM
js(
(SELECT json, type FROM [fh-bigquery:openlibrary.ol_dump_20151231]
),
// Input columns.
json, type,
// Output schema.
"[{name: 'key', type:'string'},
{name: 'type', type:'string'}]",
// The function.
"function(r, emit) {
x=JSON.parse(r.json)
Object.keys(x).forEach(function(entry) {
emit({key:entry, type:r.type,});
});
}"
)
)
LIMIT 100
(根据https://openlibrary.org/developers/dumps从Open Library数据转储reddit conversation获取的样本数据)
答案 2 :(得分:1)
这里使用Standard SQL:
CREATE TEMP FUNCTION jsonObjectKeys(input STRING)
RETURNS Array<String>
LANGUAGE js AS """
return Object.keys(JSON.parse(input));
""";
WITH keys AS (
SELECT
jsonObjectKeys(myColumn) AS keys
FROM
myProject.myTable
WHERE myColumn IS NOT NULL
)
SELECT
DISTINCT k
FROM keys
CROSS JOIN UNNEST(keys.keys) AS k
ORDER BY k
答案 3 :(得分:0)
这就是我提出的(特别是对于StandardSQL)..不确定在列表中累积是否是最好的方法...另外..我简化了我的情况,我只关心键。
create-react-app
答案 4 :(得分:0)
上述答案在当前 (2021) 版本中效果不佳,如果 JSON 字段为空或 JSON 具有空条目,则失败,不能很好地聚合(我们正在尝试获取结构,而不是内容) 等。
所以,这是基于 Felipe Hoffa 的 answer 的改进版本。
它是完全递归的;检查 null
和 Array
类型;抑制数组索引(如 []
);标记为确定性的,因此它会被缓存;并对结果进行分组、排序和计数。
示例输出:
key type n
"" null 213
avatar string 1046
blinking boolean 1046
created_at string 1046
deprecated_fields Array 1046
display_name string 1046
fields Array 1046
fields.[] Object 31
fields.[].name string 31
fields.[].value string 31
fields.[].verified_at null 27
fields.[].verified_at string 4
friends_count number 1046
注意:
deprecated_fields
键是 JSON 中所有示例都为 ..., deprecated_fields: [], ...
的键null
作为字符串 "null"
返回,与其他类型一样(不是 SQL null)可以改进检测不同类型的数字(int、bigint、float、decimal)、日期、存储为字符串的数字等。但是呃,这对我的目的来说已经足够了,而且需要更多的处理。
只需更改最后几行中的 your-*
位:
CREATE TEMP FUNCTION jsonParsed(input STRING)
RETURNS Array<Struct<key STRING, type STRING>>
DETERMINISTIC LANGUAGE js AS
"""
function processKey(node, parent) {
var ary = [];
if (parent !== '') {
parent += '.';
}
if (node == null) {
ary.push({
key: parent,
type: 'null'
})
} else {
Object.keys(node).map(function(key) {
var v = node[key];
if (node.constructor.name == "Array") {
keytouse = '[]'
} else {
keytouse = key
}
if ((v == null) || (typeof(v) !== 'object')) {
if (v == null) { typetouse = 'null';} else {typetouse = typeof(v);}
ary.push({
key: parent + keytouse,
type: typetouse
});
} else {
ary.push({
key: parent + keytouse,
type: v.constructor.name
});
ary = [].concat(ary, processKey(v, parent + keytouse));
}
});
}
return ary;
}
return processKey(JSON.parse(input), '');
""";
with keys as (SELECT jsonParsed(your-json-field) as keys FROM `your-project-id.your-database-id.your-table-id`)
select key, type, count(*) as n from keys k cross join unnest(k.keys) as kk group by key, type order by key asc;