9

この 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"
        ]
    }
}

目的


$aその JSON を解析して、(where is my target data)に相当する PHP に評価されるようにします。

$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 オペレーターメソッドを呼び出すことです。

クエリに一致すると仮定すると$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;

2 番目のステップ:

$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;

3 番目のステップ:

$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;

4 番目のステップ:

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

すべての値がブール値であるため、評価は を返し!in_array(false, $query, true)ます。

より良いアプローチが存在する場合は、お知らせください。

問題: 親配列キーへのアクセス


最も内側の要素と関連する (演算子を無視する) 配列 index 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()メソッドがなければ、単に配列を foreach するよりもあまり利点がないようです。

助言がありますか?

4

1 に答える 1

3

私はすぐにあなたの質問を読みました。あなたはリーフにアクセスして、それらへの主要なパスを知りたいようです。

だからここに:

$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();
}
于 2012-12-28T17:45:30.250 に答える