sql >> Database >  >> NoSQL >> MongoDB

Implementatie van goMongoDB-achtige Query-expressie-objectevaluatie

Inleiding

Ik denk dat het evalueren van MongoDB-achtige JSON-query's in PHP alle informatie heeft gegeven die je nodig hebt. je hoeft alleen maar creatief te zijn met de oplossing en je bereikt wat je wilt

De array

Laten we aannemen dat we de volgende json . hebben geconverteerd naar 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);

Voorbeeld 1

controleer of key - Different zou zo simpel zijn als

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

Uitgang

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

Voorbeeld 2 Controleer of release year is 2013

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

Uitgang

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

Voorbeeld 3

Tel waar Year is 2012

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

Voorbeeld 4

Laten we uit uw voorbeeld nemen waar u version wilt controleren is grater than 22

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

Uitgang

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

Voorbeeld 5

Controleer of release.arch waarde is IN een set zoals [x86,x100] (Voorbeeld)

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

Uitgang

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
        )

)

Voorbeeld 6

Oproepbaar gebruiken

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

Uitgang

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

)

Voorbeeld 7

Registreer uw eigen uitdrukkingsnaam

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

Uitgang

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

Klasse gebruikt

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

Samenvatting

Het dekt mogelijk niet alle geavanceerde functies en zou een uitbreidbare architectuur moeten hebben

De bovenstaande klasse toont een typisch voorbeeld van wat je wilt .. je kunt gemakkelijk decouple it , breid het uit om samengestelde uitdrukkingen zoals $and . te ondersteunen en $or

MongoDB-achtige query-expressie-objecten zijn gemakkelijk te begrijpen en te gebruiken, en bieden de mogelijkheid om schone, zelfverklarende code te schrijven, omdat zowel de query als de objecten om in te zoeken associatieve arrays zijn.

Waarom schrijf je de array niet gewoon naar een MongoDB database in plaats van te werken in arrays ?? Het is efficiënter en het zou u veel problemen besparen

Ik moet ook vermelden dat gebruik de beste tool voor de beste baan ... Wat je wilt is in feite een functie van een database

Eigenlijk is het een handige functie om informatie uit php-arrays te extraheren. Als u de arraystructuur kent (het arrayPath), kunt u bewerkingen uitvoeren op multidimensionale arraygegevens, zonder dat er meerdere geneste lussen nodig zijn.

Het voorbeeld laat zien hoe u een pad gebruikt om naar waarde te zoeken, maar u bent nog steeds afhankelijk van het laden van de array in het geheugen en uw klasse die meerdere recursie- en lussen uitvoert, wat niet zo efficiënt is als een database.

Ik waardeer architectuurtips, gerelateerde of vergelijkbare code, die een goed praktijkvoorbeeld kunnen zijn om php "if..else"-expressies on-the-fly te bouwen.

Bedoel je echt dat je al die mensen hier gewoon wilt hebben ???



  1. Wat zijn HBase-verdichtingen?

  2. mongoexport zonder _id-veld

  3. MongoDB $replaceAll

  4. Hoe een node.js met redis op kubernetes te implementeren?