【发布时间】:2013-02-04 23:48:55
【问题描述】:
我一直在寻找类似MongoDb的(http://docs.mongodb.org/manual/applications/read/#find,docs.mongodb.org/manual/reference/operators/)查询表达式对象评估函数 实现或类。它可能不会涵盖所有高级功能,并且应该具有可扩展的架构。
类似 MongoDB 的查询表达式对象易于理解和使用,提供编写简洁、自解释代码的能力,因为查询和要搜索的对象都是关联数组。
基本上说它是一个从 php 数组中提取信息的便捷函数。知道了数组结构(arrayPath),就可以对多维数组数据进行操作,而不需要多个嵌套循环。
如果您不熟悉 MongoDb,请查看要搜索的给定表达式对象和数组。
为了简单起见,我把它写成 JSON 字符串。对象内容没有意义,只是显示了 MongoDb 查询语法。
类 MongoDb 查询表达式对象
{
"name": "Mongo",
"type": "db",
"arch": {
"$in": [
"x86",
"x64"
]
},
"version": {
"$gte": 22
},
"released": {
"$or": {
"$lt": 2013,
"$gt": 2012
}
}
}
要搜索的数组
[
{
"name": "Mongo",
"type": "db",
"release": {
"arch": "x86",
"version": 22,
"year": 2012
}
},
{
"name": "Mongo",
"type": "db",
"release": {
"arch": "x64",
"version": 21,
"year": 2012
}
},
{
"name": "Mongo",
"type": "db",
"release": {
"arch": "x86",
"version": 23,
"year": 2013
}
}
]
使用类似 Mongo 的查询表达式查找
所以,在函数的帮助下,我们应该能够向目标数组发出以下查询。
$found=findLikeMongo($array, $queryExpr); //resulting in a $array[0] value;
//@return found array
使用类似 Mongo 的查询表达式获取数组路径
$arrayPath=getPathFromMongo($array, $queryExpr);// resulting in array("0")
//@return array path, represented as an array where entries are consecutive keys.
家庭作业
我发现 gossner.net/articles/JsonPath/ 可能 满足我的需求(不是完全匹配,因为它使用类似 Xpath 表达式),需要注意的是,它严重依赖于正则 表达式和字符串解析,什么肯定会减慢它 与仅数组(类似 JSON)实现相比。
我也在这里找到了一个类似的问题,@stackoverflow Evaluating MongoDB-like JSON Queries in PHP。 得到的答案是使用我使用的一些 SPL 函数 避免大部分时间。
想知道作者是否想出了函数,他一直在尝试 发展。可能的 arrayPath 实现位于 thereisamoduleforthat.com/content/dealing-deep-arrays-php, 因此缺乏这种实现,是它依赖于指针。
我知道这不是一个简单的问题,这就是为什么我在开始我自己的课程的实际开发之前问它的原因。
我很欣赏架构技巧、相关或类似代码,这可能是构建 php "if..else" 表达式的良好实践示例。强调文本
非SPL版本如何写?
@Baba 提供了一个使用 SPL 编写的优秀类。 我想知道如何在没有 SPL 的情况下重写此代码。
有两个原因
- 多次调用该类会产生函数开销,这可以避免在原始 PHP 中重写它。
- 它很容易移植到 SPL 不可用的原始 Javascript,从而在两个平台上更容易代码维护。
结果
在 Github 上创建的 ArrayQuery class is published,考虑签出存储库以获取更新。
SPL、原始 PHP 版本和 Chequer2 FORP profiler 输出
简而言之-
- 原始 PHP 版本的执行速度比 SPL 版本快 10 倍,消耗 内存减少 20%。
- Chequer2 类的执行速度比 PHP SPL 类慢 40%,并且几乎 比原始 PHP 版本慢 20 倍。
- MongoDb 是最快的(比原始 PHP 实现快 10 倍,消耗的内存少 5 倍),做 除非您确定要避免,否则不要使用这些类 与 MongoDb 交互。
MongoDb 版本
SPL 版本
原始 PHP(最新的 ArrayQuery 类)版本
Checker2 版本
MongoDb 参考测试分析代码
$m = new MongoClient(); // connect
$db = $m->testmongo; // select a database
$collection = $db->data;
$loops=100;
for ($i=0; $i<$loops; $i++) {
$d = $collection->find(array("release.year" => 2013));
}
print_r( iterator_to_array($d) );
带有 SPL 类分析代码的 PHP
include('data.php');
include('phpmongo-spl.php');
$s = new ArrayCollection($array, array("release.year" => 2013),false);
$loops=100;
for ($i=0; $i<$loops; $i++) {
$d = $s->parse();
}
print_r( $d );
SPL 类 parse() 函数稍作修改,执行后返回值,也可以修改为接受表达式,但它对于分析目的并不是必需的,因为每次都会重新评估表达式。
原始 PHP(最新的 ArrayQuery 类)分析代码
include('data.php');
include('phpmongo-raw.php');
$s = new ArrayStandard($array);
$loops=100;
for ($i=0; $i<$loops; $i++) {
$d = $s->find(array("release.year" => 2013));
}
print_r( $d );
checker2 PHP 分析代码
<?php
include('data.php');
include('../chequer2/Chequer.php');
$query=array("release.year" => 2013);
$loops=100;
for ($i=0; $i<$loops; $i++) {
$result=Chequer::shorthand('(.release.year > 2012) ? (.) : NULL')
->walk($array);
}
print_r($result);
?>
使用的数据(与@baba 在他的回答中提供的相同)
$json = '[{
"name":"Mongo",
"type":"db",
"release":{
"arch":"x86",
"version":22,
"year":2012
}
},
{
"name":"Mongo",
"type":"db",
"release":{
"arch":"x64",
"version":21,
"year":2012
}
},
{
"name":"Mongo",
"type":"db",
"release":{
"arch":"x86",
"version":23,
"year":2013
}
},
{
"key":"Diffrent",
"value":"cool",
"children":{
"tech":"json",
"lang":"php",
"year":2013
}
}
]';
$array = json_decode($json, true);
forp-ui 稍作修改的示例 ui 加载器(使用 ?profile=FILE_TO_PROFILE 调用)
<!doctype html>
<html>
<head>
<style>
body {margin : 0px}
</style>
</head>
<body>
<div class="forp"></div>
<?php
register_shutdown_function(
function() {
// next code can be append to PHP scripts in dev mode
?>
<script src="../forp-ui/js/forp.min.js"></script>
<script>
(function(f) {
f.find(".forp")
.each(
function(el) {
el.css('margin:50px;height:300px;border:1px solid #333');
}
)
.forp({
stack : <?php echo json_encode(forp_dump()); ?>,
//mode : "fixed"
})
})(forp);
</script>
<?php
}
);
// start forp
forp_start();
// our PHP script to profile
include($_GET['profile']);
// stop forp
forp_end();
?>
</body>
</html>
【问题讨论】:
标签: php mongodb if-statement multidimensional-array query-expressions