【问题标题】:Evaluating MongoDB-like JSON Queries in PHP在 PHP 中评估类似 MongoDB 的 JSON 查询
【发布时间】:2012-12-13 18:35:54
【问题描述】:

考虑在这个 JSON 对象中表达的以下(相当复杂的)查询:

{
    "name": "Kindle Fire",
    "sale": true,
    "price": {
        "$gt": 199,
        "$lt": 264
    },
    "price.vat": { // bogus, just to show $a['price.vat'] == $a['price']['vat']
        "$lte": 1.2
    },
    "$or": {
        "qty": {
            "$gt": 30
        },
        "eta": {
            "$or": {
                "$lt": 3,
                "$gt": 30
            }
        }
    },
    "countriesAvailable": {
        "$in": [
            "US",
            "CA"
        ]
    }
}

目标


我想解析该 JSON,以便它计算为 PHP 等效项(其中$a 是我的目标数据):

$a['name'] == 'Kindle Fire' &&
$a['sale'] == true &&
(
    $a['price'] > 199 && $a['price'] < 264
) &&
$a['price']['vat'] <= 1.2 &&
(
    $a['qty'] > 30 ||
    (
        $a['eta'] < 3 || $a['eta'] > 30
    )
) &&
in_array($a['countriesAvailable'], array('US', 'CA'))

我几乎没有构建表达式评估器的经验。我的想法是从最内层到最外层遍历查询,根据需要调用对应的MongoDB operator方法。

假设$a 匹配查询,这将是评估计划:

$query = array();
$query['name'] = true;
$query['sale'] = true;
$query['price'] = array();
$query['price']['$gt'] = true;
$query['price']['$lt'] = true;
$query['price']['vat'] = array();
$query['price']['vat']['$lte'] = true;
$query['$or'] = array();
$query['$or']['qty'] = array();
$query['$or']['qty']['$gt'] = false;
$query['$or']['eta'] = array();
$query['$or']['eta']['$or'] = array();
$query['$or']['eta']['$or']['$lt'] = true;
$query['$or']['eta']['$or']['$gt'] = false;
$query['countriesAvailable'] = array();
$query['countriesAvailable']['$in'] = true;

第二步:

$query = array();
$query['name'] = true;
$query['sale'] = true;
$query['price'] = array();
$query['price']['$gt'] = true;
$query['price']['$lt'] = true;
$query['price']['vat'] = true;
$query['$or'] = array();
$query['$or']['qty'] false;
$query['$or']['eta'] = array();
$query['$or']['eta']['$or'] true;
$query['countriesAvailable'] = true;

第三步:

$query = array();
$query['name'] = true;
$query['sale'] = true;
$query['price'] = true;
$query['$or'] = array();
$query['$or']['qty'] false;
$query['$or']['eta'] true;
$query['countriesAvailable'] = true;

第四步:

$query = array();
$query['name'] = true;
$query['sale'] = true;
$query['price'] = true;
$query['$or'] = true;
$query['countriesAvailable'] = true;

由于所有值都是布尔值,因此评估结束返回!in_array(false, $query, true)

如果有更好的方法,请告诉我。

问题:访问父数组键


我一直在尝试获取最里面的元素和相关(忽略运算符)数组索引 path,例如,如果我使用 RecursiveIteratorIterator,我会得到第一个的正确值迭代:

$nodes = new ArrayIterator($query);
$iterator = new RecursiveArrayIterator($nodes);
$iteratorIterator = new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::LEAVES_ONLY);

print_r(iterator_to_array($iteratorIterator));

Array
(
    [name] => Kindle Fire HD
    [sale] => 1
    [$gt] => 30
    [$lt] => 3
    [$lte] => 1.2
    [0] => US
    [1] => CA
)

但是,它几乎没有用,因为我无法确定键所指的$a 索引,更不用说键值被后面的条目覆盖以及我无法更改它们的值的事实。

我也尝试过使用 RecursiveArrayIterator,但如果没有 hasParent() / getParent() 方法,与简单地遍历数组相比,它似乎没有给我太多优势。

有什么建议吗?

【问题讨论】:

  • $a['price'] &gt; 199 当它是一个数组 ($a['price']['vat'] &lt;= 1.2) 时将没有意义。
  • @dev-null-dweller:确实如此。这是一个虚拟的例子,请忽略它。
  • 访问父数组键的函数:stackoverflow.com/questions/2504685/…
  • @JirilmonGeorge:这似乎大致相当于array_search($needle, $iteratorIterator);,不知道这对我有什么帮助。

标签: php arrays multidimensional-array iterator evaluation


【解决方案1】:

我很快就阅读了您的问题,听起来您想访问叶子并了解它们的关键路径。

所以这里:

$ritit = new RecursiveIteratorIterator(new RecursiveArrayIterator($myArray));
foreach ($ritit as $leafValue) {
    $keyPath = array();
    foreach (range(0, $ritit->getDepth()) as $depth) {
        $keyPath[] = $ritit->getSubIterator($depth)->key();
    }
    // do something with $keyPath


    // or
    $hasParent = $ritit->getDepth() > 0;
    $parentIter = $ritit->getSubIterator($ritit->getDepth() - 1);
    $parentKey = $parentIter->key();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-02
    • 2013-02-04
    • 2012-01-14
    • 2013-03-09
    • 2022-06-28
    • 1970-01-01
    • 2016-03-11
    相关资源
    最近更新 更多