sql >> Databáze >  >> NoSQL >> MongoDB

Implementace vyhodnocení objektu výrazu dotazu typu goMongoDB

Úvod

Myslím, že vyhodnocení dotazů JSON podobných MongoDB v PHP poskytlo všechny informace, které potřebujete. vše, co potřebujete, je být kreativní s řešením a dosáhnete toho, co chcete

Pole

Předpokládejme, že máme následující json převeden na pole

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

Příklad 1

zkontrolujte, zda key - Different by bylo stejně jednoduché jako

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

Výstup

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

Příklad 2 Zkontrolujte, zda release year je 2013

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

Výstup

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

Příklad 3

Počítejte kde Year je 2012

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

Příklad 4

Vezměme si z vašeho příkladu, kde chcete zkontrolovat version je grater than 22

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

Výstup

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

Příklad 5

Zkontrolujte, zda release.arch hodnota je IN sadu jako [x86,x100] (Příklad)

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

Výstup

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
        )

)

Příklad 6

Pomocí 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);
}

Výstup

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

)

Příklad 7

Zaregistrujte svůj vlastní název výrazu

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

Výstup

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

Použitá třída

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

Shrnutí

Nemusí pokrývat všechny pokročilé funkce a měl by mít rozšiřitelnou architekturu

Výše uvedená třída ukazuje typický příklad toho, co chcete .. můžete snadno decouple jej rozšiřte o podporu složených výrazů jako $and a $or

Objekty dotazového výrazu podobné MongoDB jsou snadno pochopitelné a použitelné a poskytují možnost psát čistý, samovysvětlující kód, protože jak dotaz, tak objekty k vyhledávání, jsou asociativní pole.

Proč prostě nezapsat pole do MongoDB databáze spíše než pracovat s poli? Je to efektivnější a ušetří vám to spoustu problémů

Musím také zmínit, že používejte nejlepší nástroj pro nejlepší práci ... To, co chcete, je v podstatě funkce databáze

V podstatě jde o pohodlnou funkci pro extrahování informací z polí php. Díky znalosti struktury pole (polePath) bude možné provádět operace s daty vícerozměrných polí bez potřeby více vnořených smyček.

Příklad ukazuje, jak používat cestu k hledání hodnoty, ale stále jste závislí na načtení pole do paměti a na vaší třídě provádějící více rekurzí a smyček, což není tak efektivní jako databáze.

Oceňuji tipy na architekturu, související nebo podobný kód, což může být příklad dobré praxe pro vytváření php výrazů „if..else“ za běhu.

Opravdu to myslíte, že chcete všechny jen tady???



  1. Jak bych měl používat Booksleeve s protobuf-net?

  2. Výukový program MongoDB pro rok 2022 – Zjistěte, co je MongoDB?

  3. Možnost shody příkazu Redis scan nefunguje v Pythonu

  4. Jak ukončit platnost podřízeného klíče HSET v redis?