是否有(大致)SQL 或类似 XQuery 的语言来查询 JSON?
我正在考虑可以很好地映射到 JSON 的非常小的数据集,在其中很容易回答诸如“Y > 3 时 X 的所有值是多少”之类的查询,或者执行通常的 SUM / COUNT 类型操作。
作为完全虚构的示例,如下所示:
[{"x": 2, "y": 0}}, {"x": 3, "y": 1}, {"x": 4, "y": 1}]
SUM(X) WHERE Y > 0 (would equate to 7)
LIST(X) WHERE Y > 0 (would equate to [3,4])
我认为这在客户端和服务器端都可以工作,结果将被转换为适当的特定于语言的数据结构(或者可能保存为 JSON)
快速谷歌搜索表明人们已经考虑过并实现了一些东西(JAQL),但似乎还没有出现标准用法或一组库。虽然每个功能单独实现都相当简单,但如果有人已经做对了,我不想重新发明轮子。
有什么建议么?
编辑:这可能确实是个坏主意,或者 JSON 可能是我所想的过于通用的格式。想要一种查询语言而不是根据需要直接执行 summing/etc 函数的原因是我希望构建根据用户输入动态查询。有点像“我们不需要 SQL,我们可以编写我们需要的函数”的论点。最终,要么失控,要么您最终编写自己的 SQL 版本,因为您将其推得越来越远。 (好吧,我知道这是一个有点愚蠢的论点,但你明白了..)
当然,怎么样:
json路径。
json查询
它们似乎都在进行中,但在某种程度上都在起作用。它们在概念上也类似于 XPath 和 XQuery;即使 XML 和 JSON 具有不同的概念模型(分层与对象/结构)。
编辑 2015 年 9 月:实际上现在有 JSON Pointer 标准允许非常简单和有效地遍历 JSON 内容。它不仅被正式指定,而且被许多 JSON 库支持。因此,我将其称为实际真正有用的标准,尽管由于其表达能力有限,它本身可能被视为查询语言,也可能不被视为查询语言。
I'd recommend my project I'm working on called jLinq。我正在寻找反馈,所以我很想听听你的想法。
如果允许您编写类似于在 LINQ 中的查询...
var results = jLinq.from(records.users)
//you can join records
.join(records.locations, "location", "locationId", "id")
//write queries on the data
.startsWith("firstname", "j")
.or("k") //automatically remembers field and command names
//even query joined items
.equals("location.state", "TX")
//and even do custom selections
.select(function(rec) {
return {
fullname : rec.firstname + " " + rec.lastname,
city : rec.location.city,
ageInTenYears : (rec.age + 10)
};
});
它也是完全可扩展的!
文档仍在进行中,但您仍然可以在线尝试。
更新:XQuery 3.1 可以查询 XML 或 JSON - 或同时查询两者。 XPath 3.1 也可以。
该列表正在增长:
JSONiq(基于 XQuery)
UNQL(如 SQL)
JaQL(函数式)
JsonPath(类似 XPath)
Json Query(类似于 XPath)
GraphQL(基于模板,类型化)
JMESPath 工作起来非常简单而且效果很好:http://jmespath.org/。它有一个完整的规范和多种语言的库。 Amazon 在 AWS 命令行界面中使用它,因此它必须非常稳定。
语法示例:
// Select a single item
people[1].firstName
// Select a slice of an array
people[0:5]
// Select all the first names
people[*].firstName
// Select all first names based on search term
people[?state=='VA'].firstName
// Count how many people are over 35
length(people[?age>`35`])
// Select only the name and age of people over 35
people[?age>`35`].{name: name, age: age}
// Join expressions together to sort and join elements into a string
people[?state == 'WA'].name | sort(@) | join(', ', @)
您可以在 the docs 中使用更多实时示例。
jmespath
用于 --query
参数,但建议将 jq
用于命令行管道。 docs.aws.amazon.com/cli/latest/userguide/…
jq 是一种 JSON query 语言,主要用于命令行,但绑定到多种编程语言(Java、node.js、php , ...),甚至可以通过 jq-web 在浏览器中使用。 jq 基于 C 的实现通常称为“jq”,基于 Go 的版本称为 "gojq"。
以下是基于原始问题的一些插图,以这个 JSON 为例:
[{"x": 2, "y": 0}}, {"x": 3, "y": 1}, {"x": 4, "y": 1}]
SUM(X) 其中 Y > 0(等于 7)
map(select(.y > 0)) | add
LIST(X) WHERE Y > 0(相当于 [3,4])
map(.y > 0)
jq 语法扩展了 JSON 语法
每个 JSON 表达式都是一个有效的 jq 表达式,[1, (1+1)]
和 {"a": (1+1)}` 等表达式说明了 jq 如何扩展 JSON 语法。
一个更有用的例子是 jq 表达式:
{a,b}
给定 JSON 值 {"a":1, "b":2, "c": 3}
,其计算结果为 {"a":1, "b":2}
。
内置的 array.filter()
method 使这些所谓的 javascript 查询库中的大多数都过时了
您可以在委托中放置尽可能多的条件:简单比较、startsWith 等。我还没有测试过,但您也可以嵌套过滤器来查询内部集合。
array.filter()
是 JavaScript 的一部分,而不是 JSON。
filter()
可用于“查询”JSON 对象,但有一个缺点:它接受函数而不是字符串。因此,您不能通过网络使用它作为参数传递。
另一种看待这个问题的方法是使用 mongoDB 您可以将 JSON 存储在 mongo 中,然后通过 mongodb 查询语法对其进行查询。
ObjectPath 是用于复杂或未知结构的 JSON 文档的简单且轻量级的查询语言。它类似于 XPath 或 JSONPath,但由于嵌入式算术计算、比较机制和内置函数而更强大。
https://i.stack.imgur.com/G2d5K.png
Python 版本成熟并用于生产。 JS 仍处于测试阶段。
可能在不久的将来,我们将提供一个成熟的 Javascript 版本。我们还想进一步开发它,以便它可以作为 Mongo 查询的更简单替代方案。
好的,这篇文章有点老了,但是……如果您想在 JS 对象上使用原生 JSON(或 JS 对象)进行类似 SQL 的查询,请查看 https://github.com/deitch/searchjs
它既是一种完全用 JSON 编写的 jsql 语言,又是一种参考实现。你可以说,“我想在一个数组中找到 name==="John" && age===25 的所有对象:
{name:"John",age:25,_join:"AND"}
参考实现 searchjs 在浏览器以及节点 npm 包中工作
npm install searchjs
它还可以执行复杂连接和否定 (NOT) 之类的操作。它本机忽略大小写。
它还没有进行求和或计数,但在外面做这些可能更容易。
如果你想使用纯 javascript 试试这个:
var object = { result: { data: { point1: "x", value: 2 }, foo: { bar: 7 } } }, path = 'result.data.value', getValue = (o, p) => p.split('.').reduce((r, k) => r[k], o); console.log(getValue(object, path));
这里有一些简单的 JavaScript 库也可以解决问题:
Dollar Q 是一个不错的轻量级库。它对 jQuery 流行的链接语法有一种熟悉的感觉,并且只有 373 SLOC。
SpahQL 是一种功能齐全的查询语言,其语法类似于 XPath (Homepage, Github
jFunk 是一种进行中的查询语言,其语法类似于 CSS/jQuery 选择器。它看起来很有希望,但除了最初的提交之外没有任何发展。
(2014 年添加):jq 命令行工具语法简洁,但不幸的是它是 ac 库。示例用法:< package.json jq '.dependencies | to_entry | .[] |选择(.value | 开始(“git”)) | 。钥匙'
在 MongoDB 中,这就是它的工作方式(在 mongo shell 中,存在用于您选择的语言的驱动程序)。
db.collection.insert({"x": 2, "y": 0}); // notice the ':' instead of ','
db.collection.insert({"x": 3, "y": 1});
db.collection.insert({"x": 4, "y": 1});
db.collection.aggregate([{$match: {"y": {$gt: 0}}},
{$group: {_id: "sum", sum: {$sum: "$x"}}}]);
db.collection.aggregate([{$match: {"y": {$gt: 0}}},
{$group: {_id: "list", list: {$push: "$x"}}}]);
前三个命令将数据插入到您的集合中。 (只需启动 mongod
服务器并与 mongo
客户端连接。)
接下来的两个处理数据。 $match
过滤器,$group
分别应用 sum
和 list
。
查看 https://github.com/niclasko/Cypher.js(注意:我是作者)
它是 Cypher 图形数据库查询语言和图形数据库的零依赖 Javascript 实现。它在浏览器中运行(用 Firefox、Chrome、IE 测试)。
与问题相关。它可用于查询 JSON 端点:
load json from "http://url/endpoint" as l return l limit 10
下面是一个查询复杂 JSON 文档并对其执行分析的示例:
您可以使用 linq.js
。
这允许从对象数据集中使用聚合和选择,作为其他结构数据。
var data = [{ x: 2, y: 0 }, { x: 3, y: 1 }, { x: 4, y: 1 }]; // SUM(X) WHERE Y > 0 -> 7 console.log(Enumerable.From(data).Where("$.y > 0").Sum("$.x")); // LIST(X) WHERE Y > 0 -> [3, 4] console.log(Enumerable.From(data).Where("$.y > 0").Select("$.x").ToArray( ));
据我所知,SpahQL 是其中最有前途和经过深思熟虑的。我强烈建议检查一下。
我刚刚完成了客户端 JS-lib (defiant.js) 的可发布版本,它可以满足您的需求。使用 defiant.js,您可以使用您熟悉的 XPath 表达式查询 JSON 结构(没有 JSONPath 中的新语法表达式)。
工作原理示例(在浏览器中查看 http://defiantjs.com/defiant.js/demo/sum.avg.htm):
var data = [
{ "x": 2, "y": 0 },
{ "x": 3, "y": 1 },
{ "x": 4, "y": 1 },
{ "x": 2, "y": 1 }
],
res = JSON.search( data, '//*[ y > 0 ]' );
console.log( res.sum('x') );
// 9
console.log( res.avg('x') );
// 3
console.log( res.min('x') );
// 2
console.log( res.max('x') );
// 4
如您所见,DefiantJS 使用搜索函数扩展了全局对象 JSON,返回的数组通过聚合函数传递。 DefiantJS 包含一些其他功能,但这些功能超出了本主题的范围。任何人,您都可以使用客户端 XPath Evaluator 测试该库。我认为不熟悉 XPath 的人会发现这个评估器很有用。
http://defiantjs.com/#xpath_evaluator
有关 defiant.js 的更多信息
http://defiantjs.com/
https://github.com/hbi99/defiant.js
我希望你觉得它有用......问候
谷歌有一个名为lovefield的项目;刚刚发现它,它看起来很有趣,尽管它比仅仅添加下划线或 lodash 更复杂。 https://github.com/google/lovefield
Lovefield 是一个用纯 JavaScript 编写的关系查询引擎。它还提供了在浏览器端持久化数据的帮助,例如使用 IndexedDB 在本地存储数据。它提供类似 SQL 的语法并且可以跨浏览器工作(目前支持 Chrome 37+、Firefox 31+、IE 10+ 和 Safari 5.1+...
这个领域最近另一个有趣的条目叫做 jinqJs。 http://www.jinqjs.com/ 简要回顾一下示例,看起来很有希望,API 文档似乎写得很好。
function isChild(row) {
return (row.Age < 18 ? 'Yes' : 'No');
}
var people = [
{Name: 'Jane', Age: 20, Location: 'Smithtown'},
{Name: 'Ken', Age: 57, Location: 'Islip'},
{Name: 'Tom', Age: 10, Location: 'Islip'}
];
var result = new jinqJs()
.from(people)
.orderBy('Age')
.select([{field: 'Name'},
{field: 'Age', text: 'Your Age'},
{text: 'Is Child', value: isChild}]);
jinqJs 是一个小型、简单、轻量级和可扩展的 JavaScript 库,没有依赖项。 jinqJs 提供了一种简单的方法来对返回 JSON 响应的 javaScript 数组、集合和 Web 服务执行类似 SQL 的查询。 jinqJs 类似于 Microsoft 的 .Net Lambda 表达式,它提供了类似的功能来使用类似 SQL 的语法和谓词功能来查询集合。 jinqJs 的目的是为熟悉 LINQ 查询的程序员提供类似 SQL 的体验。
PythonQL 提供了一种嵌入式语法,恕我直言,这是对 SQL 的改进,主要是因为 group
、window
、where
、let
等可以自由混合。
$ cat x.py
#coding: pythonql
data = [{"x": 2, "y": 0}, {"x": 3, "y": 1}, {"x": 4, "y": 1}]
q = [x match {'x': as x, 'y': as y} in data where y > 0]
print(sum(q))
print(list(q))
q = [x match {'x': as x, 'y': as y} as d in data where d['y'] > 0]
print(sum(q))
此代码显示您的问题的两个不同答案,具体取决于您处理整个结构或仅处理值的需要。执行会给你预期的结果。
$ python x.py
7
[3, 4]
7
当前的 Jaql 实现针对使用 Hadoop 集群的大型数据处理,因此它可能超出您的需要。但是,它可以在没有 Hadoop 集群的情况下轻松运行(但仍然需要 Hadoop 代码及其依赖项才能编译,大部分都包含在内)。可以嵌入到 Javascript 和浏览器中的 Jaql 的小型实现将是该项目的一个很好的补充。
您上面的示例很容易用 jaql 编写:
$data = [{"x": 2, "y": 0}, {"x": 3, "y": 1}, {"x": 4, "y": 1}];
$data -> filter $.y > 0 -> transform $.x -> sum(); // 7
$data -> filter $.y > 0 -> transform $.x; // [3,4]
当然,还有更多。例如:
// Compute multiple aggregates and change nesting structure:
$data -> group by $y = $.y into { $y, s:sum($[*].x), n:count($), xs:$[*].x};
// [{ "y": 0, "s": 2, "n": 1, "xs": [2] },
// { "y": 1, "s": 7, "n": 2, "xs": [3,4] }]
// Join multiple data sets:
$more = [{ "y": 0, "z": 5 }, { "y": 1, "z": 6 }];
join $data, $more where $data.y == $more.y into {$data, $more};
// [{ "data": { "x": 2, "y": 0 }, "more": { "y": 0, "z": 5 }},
// { "data": { "x": 3, "y": 1 }, "more": { "y": 1, "z": 6 }},
// { "data": { "x": 4, "y": 1 }, "more": { "y": 1, "z": 6 }}]
Jaql 可以在 http://code.google.com/p/jaql/ 下载/讨论
您还可以使用 Underscore.js,它基本上是一个瑞士刀库来操作集合。使用 _.filter
、_.pluck
、_.reduce
,您可以执行类似 SQL 的查询。
var data = [{"x": 2, "y": 0}, {"x": 3, "y": 1}, {"x": 4, "y": 1}];
var posData = _.filter(data, function(elt) { return elt.y > 0; });
// [{"x": 3, "y": 1}, {"x": 4, "y": 1}]
var values = _.pluck(posData, "x");
// [3, 4]
var sum = _.reduce(values, function(a, b) { return a+b; });
// 7
Underscore.js 适用于客户端和服务器端,是一个值得注意的库。
您还可以使用 Lo-Dash,它是 Underscore.js 的一个分支,具有更好的性能。
只要有可能,我会将所有查询转移到服务器上的后端(转移到 SQL DB 或其他本机数据库类型)。原因是查询会更快、更优化。
我知道 JSON 可以是独立的,并且可能有 +/- 用于查询语言,但如果您将数据从后端检索到浏览器,我看不到优势,就像大多数 JSON 用例一样。在后端查询和过滤以获取所需的尽可能小的数据。
如果出于某种原因您需要在前端查询(主要是在浏览器中),那么我建议只使用 array.filter (为什么要发明其他东西?)。
也就是说,我认为更有用的是 json 的转换 API……它们更有用,因为一旦你有了数据,你可能想以多种方式显示它。但是,同样,您可以在服务器上执行大部分操作(这可能比在客户端上更容易扩展)——如果您使用的是服务器<-->客户端模型。
只值我的 2 便士!
不定期副业成功案例分享