sql >> Database teknologi >  >> NoSQL >> MongoDB

Implementering af goMongoDB-lignende Query-udtryksobjektevaluering

Introduktion

Jeg tror, ​​at evaluering af MongoDB-lignende JSON-forespørgsler i PHP har givet al den information, du har brug for. alt hvad du behøver er at være kreativ med løsningen, og du opnår det du ønsker

Arrayet

Lad os antage, at vi har følgende json konverteret til array

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

Eksempel 1

tjek om key - Different ville være så simpelt som

echo new ArrayCollection($array, array("key" => "Diffrent"));
 

Output

{"3":{"key":"Diffrent","value":"cool","children":{"tech":"json","lang":"php","year":2013}}}
 

Eksempel 2 Tjek om release year er 2013

echo new ArrayCollection($array, array("release.year" => 2013));
 

Output

{"2":{"name":"Mongo","type":"db","release":{"arch":"x86","version":23,"year":2013}}}
 

Eksempel 3

Tæl hvor Year er 2012

$c = new ArrayCollection($array, array("release.year" => 2012));
echo count($c); // output 2 
 

Eksempel 4

Lad os tage fra dit eksempel, hvor du vil kontrollere version er grater than 22

$c = new ArrayCollection($array, array("release.version" => array('$gt'=>22)));
echo $c;
 

Output

{"2":{"name":"Mongo","type":"db","release":{"arch":"x86","version":23,"year":2013}}}
 

Eksempel 5

Tjek om release.arch værdien er IN et sæt såsom [x86,x100] (Eksempel)

$c = new ArrayCollection($array, array("release.arch" => array('$in'=>array("x86","x100"))));
foreach($c as $var)
{
    print_r($var);
}
 

Output

Array ( [name] => Mongo [type] => db [release] => Array ( [arch] => x86 [version] => 22 [year] => 2012 ) ) Array ( [name] => Mongo [type] => db [release] => Array ( [arch] => x86 [version] => 23 [year] => 2013 ) )

Eksempel 6

Bruger Callable

$year = 2013;
$expression = array("release.year" => array('$func' => function ($value) use($year) {
    return $value === 2013;
}));

$c = new ArrayCollection($array, $expression);

foreach ( $c as $var ) {
    print_r($var);
}
 

Output

Array
(
    [name] => Mongo
    [type] => db
    [release] => Array
        (
            [arch] => x86
            [version] => 23
            [year] => 2013
        )

)
 

Eksempel 7

Registrer dit eget udtryksnavn

$c = new ArrayCollection($array, array("release.year" => array('$baba' => 3)), false);
$c->register('$baba', function ($a, $b) {
    return substr($a, - 1) == $b;
});
$c->parse();
echo $c;
 

Output

{"2":{"name":"Mongo","type":"db","release":{"arch":"x86","version":23,"year":2013}}}
 

Klasse brugt

class ArrayCollection implements IteratorAggregate, Countable, JsonSerializable {
    private $array;
    private $found = array();
    private $log;
    private $expression;
    private $register;

    function __construct(array $array, array $expression, $parse = true) {
        $this->array = $array;
        $this->expression = $expression;
        $this->registerDefault();
        $parse === true and $this->parse();
    }

    public function __toString() {
        return $this->jsonSerialize();
    }

    public function jsonSerialize() {
        return json_encode($this->found);
    }

    public function getIterator() {
        return new ArrayIterator($this->found);
    }

    public function count() {
        return count($this->found);
    }

    public function getLog() {
        return $this->log;
    }

    public function register($offset, $value) {
        if (strpos($offset, '$') !== 0)
            throw new InvalidArgumentException('Expresiion name must always start with "$" sign');

        if (isset($this->register[$offset]))
            throw new InvalidArgumentException(sprintf('Expression %s already registred .. Please unregister It first'));

        if (! is_callable($value)) {
            throw new InvalidArgumentException(sprintf('Only callable value can be registred'));
        }

        $this->register[$offset] = $value;
    }

    public function unRegister($offset) {
        unset($this->register[$offset]);
    }

    public function parse() {
        $it = new RecursiveIteratorIterator(new RecursiveArrayIterator($this->array));
        foreach ( $it as $k => $items ) {
            if ($this->evaluate($this->getPath($it), $items)) {
                $this->found[$it->getSubIterator(0)->key()] = $this->array[$it->getSubIterator(0)->key()];
            }
        }
    }

    private function registerDefault() {
        $this->register['$eq'] = array($this,"evaluateEqal");
        $this->register['$not'] = array($this,"evaluateNotEqual");

        $this->register['$gte'] = array($this,"evaluateGreater");
        $this->register['$gt'] = array($this,"evaluateGreater");

        $this->register['$lte'] = array($this,"evaluateLess");
        $this->register['$lt'] = array($this,"evaluateLess");

        $this->register['$in'] = array($this,"evalueateInset");

        $this->register['$func'] = array($this,"evalueateFunction");
        $this->register['$fn'] = array($this,"evalueateFunction");
        $this->register['$f'] = array($this,"evalueateFunction");
    }

    private function log($log) {
        $this->log[] = $log;
    }

    private function getPath(RecursiveIteratorIterator $it) {
        $keyPath = array();
        foreach ( range(1, $it->getDepth()) as $depth ) {
            $keyPath[] = $it->getSubIterator($depth)->key();
        }
        return implode(".", $keyPath);
    }

    private function checkType($a, $b) {
        if (gettype($a) != gettype($b)) {
            $this->log(sprintf("%s - %s  is not same type of %s - %s", json_encode($a), gettype($a), json_encode($b), gettype($b)));
            return false;
        }
        return true;
    }

    private function evaluate($key, $value) {
        $o = $r = 0; // Obigation & Requirement
        foreach ( $this->expression as $k => $options ) {
            if ($k !== $key)
                continue;

            if (is_array($options)) {
                foreach ( $options as $eK => $eValue ) {
                    if (strpos($eK, '$') === 0) {
                        $r ++;
                        $callable = $this->register[$eK];
                        $callable($value, $eValue) and $o ++;
                    } else {
                        throw new InvalidArgumentException('Missing "$" in expession key');
                    }
                }
            } else {

                $r ++;
                $this->evaluateEqal($value, $options) and $o ++;
            }
        }
        return $r > 0 && $o === $r;
    }

    private function evaluateEqal($a, $b) {
        return $a == $b;
    }

    private function evaluateNotEqual($a, $b) {
        return $a != $b;
    }

    private function evaluateLess($a, $b) {
        return $this->checkType($a, $b) and $a < $b;
    }

    private function evaluateGreater($a, $b) {
        return $this->checkType($a, $b) and $a > $b;
    }

    private function evalueateInset($a, array $b) {
        return in_array($a, $b);
    }

    private function evalueateFunction($a, callable $b) {
        return $b($a);
    }
}
 

Oversigt

Det dækker muligvis ikke alle de avancerede funktioner og bør have en udvidelsesbar arkitektur

Ovenstående klasse viser et typisk eksempel på, hvad du ønsker .. du kan nemt decouple it , udvide det til at understøtte sammensatte udtryk som $and og $or

MongoDB-lignende forespørgselsudtryksobjekter er nemme at forstå og bruge, hvilket giver mulighed for at skrive ren, selvforklarende kode, fordi både forespørgsler og objekter at søge i er associative arrays.

Hvorfor ikke bare skrive arrayet til en MongoDB database snarere end at arbejde med det arrays ?? Det er mere effektivt, og det ville spare dig for mange problemer

Jeg må også nævne, at brug det bedste værktøj til det bedste job ... Det du ønsker er dybest set en funktion af en database

Dybest set taler det om en praktisk funktion til at udtrække information fra php-arrays. Ved at kende array-strukturen (arrayPath), vil det gøre det muligt at udføre operationer på multidimensionelle array-data uden behov for flere indlejrede sløjfer.

Eksemplet viser, hvordan du bruger en sti til at søge efter værdi, men du er stadig afhængig af at indlæse arrayet til hukommelsen, og at din klasse udfører flere rekursion og loops, hvilket ikke er så effektivt som en database.

Jeg sætter pris på arkitekturtips, relateret eller lignende kode, som kan være et eksempel på god praksis til at bygge php "hvis..else"-udtryk i farten.

Mener du virkelig, at du vil have alle dem herinde ???



  1. Forespørgsel med strengdatoformat i mongodb

  2. mongodb grupperer værdier efter flere felter

  3. Er der en god måde at støtte popmedlemmer fra Redis Sorted Set?

  4. MongoDB:Hvordan finder man ud af, om et array-felt indeholder et element?