Note that there are some explanatory texts on larger screens.

plurals
  1. POEvaluating MongoDB-like JSON Queries in PHP
    primarykey
    data
    text
    <p>Consider the following (rather complicated) query expressed in this JSON object:</p> <pre><code>{ "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" ] } } </code></pre> <h2>Objective</h2> <hr> <p>I want to parse that JSON so that it evaluates to the PHP equivalent of (where <code>$a</code> is my target data):</p> <pre><code>$a['name'] == 'Kindle Fire' &amp;&amp; $a['sale'] == true &amp;&amp; ( $a['price'] &gt; 199 &amp;&amp; $a['price'] &lt; 264 ) &amp;&amp; $a['price']['vat'] &lt;= 1.2 &amp;&amp; ( $a['qty'] &gt; 30 || ( $a['eta'] &lt; 3 || $a['eta'] &gt; 30 ) ) &amp;&amp; in_array($a['countriesAvailable'], array('US', 'CA')) </code></pre> <p>I have little experience building expression evaluators. My idea is to traverse the query from the innermost level to the outermost level, calling the corresponding <a href="http://docs.mongodb.org/manual/reference/operators/">MongoDB operator</a> methods as needed.</p> <p>Assuming <code>$a</code> matches the query, this would be the evaluation plan:</p> <pre><code>$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; </code></pre> <p>The second step:</p> <pre><code>$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; </code></pre> <p>The third step:</p> <pre><code>$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; </code></pre> <p>The fourth step:</p> <pre><code>$query = array(); $query['name'] = true; $query['sale'] = true; $query['price'] = true; $query['$or'] = true; $query['countriesAvailable'] = true; </code></pre> <p>Since all the values are booleans the evaluation ends returning <code>!in_array(false, $query, true)</code>.</p> <p>If a better approach exists, let me know.</p> <h2>Problem: Accessing Parent Array Keys</h2> <hr> <p>I'm stuck trying to get the innermost the elements and the relevant (ignoring operators) array index <em>path</em>, for instance, if I use a <code>RecursiveIteratorIterator</code> I get the correct values for the first iteration:</p> <pre><code>$nodes = new ArrayIterator($query); $iterator = new RecursiveArrayIterator($nodes); $iteratorIterator = new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::LEAVES_ONLY); print_r(iterator_to_array($iteratorIterator)); Array ( [name] =&gt; Kindle Fire HD [sale] =&gt; 1 [$gt] =&gt; 30 [$lt] =&gt; 3 [$lte] =&gt; 1.2 [0] =&gt; US [1] =&gt; CA ) </code></pre> <p>However, it's of little use since I cannot be sure what <code>$a</code> index the keys are referring to, not to mention that the key values are being overwritten by latter entries and the fact that I can't change their values.</p> <p>I've also tried playing with <a href="http://php.net/manual/en/class.recursivearrayiterator.php"><code>RecursiveArrayIterator</code></a>, but without the <code>hasParent()</code> / <code>getParent()</code> methods it doesn't seem to give me much advantage over simply foreach'ing the array.</p> <p>Any suggestions?</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload