MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Implementieren der goMongoDB-ähnlichen Auswertung von Abfrageausdrucksobjekten

Einführung

Ich denke, das Auswerten von MongoDB-ähnlichen JSON-Abfragen in PHP hat alle Informationen geliefert, die Sie benötigen. Alles, was Sie brauchen, ist, mit der Lösung kreativ zu sein, und Sie erreichen, was Sie wollen

Das Array

Nehmen wir an, wir haben den folgenden json in ein Array umgewandelt

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

Beispiel 1

prüfen ob key - Different wäre so einfach wie

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

Ausgabe

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

Beispiel 2 Überprüfen Sie, ob release year ist 2013

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

Ausgabe

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

Beispiel 3

Zählen Sie dabei Year ist 2012

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

Beispiel 4

Nehmen wir aus Ihrem Beispiel, wo Sie version überprüfen möchten ist grater than 22

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

Ausgabe

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

Beispiel 5

Prüfen Sie, ob release.arch Wert ist IN ein Satz wie [x86,x100] (Beispiel)

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

Ausgabe

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
        )

)

Beispiel 6

Callable

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

Ausgabe

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

)

Beispiel 7

Registrieren Sie Ihren eigenen Ausdrucksnamen

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

Ausgabe

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

Verwendete Klasse

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

Zusammenfassung

Es deckt möglicherweise nicht alle erweiterten Funktionen ab und sollte über eine erweiterbare Architektur verfügen

Die obige Klasse zeigt ein typisches Beispiel dafür, was Sie wollen. Sie können einfach decouple it , erweitern Sie es, um zusammengesetzte Ausdrücke wie $and zu unterstützen und $or

MongoDB-ähnliche Abfrageausdrucksobjekte sind einfach zu verstehen und zu verwenden und bieten die Möglichkeit, sauberen, selbsterklärenden Code zu schreiben, da sowohl die Abfrage als auch die zu durchsuchenden Objekte assoziative Arrays sind.

Warum schreiben Sie das Array nicht einfach in eine MongoDB Datenbank, anstatt es mit Arrays zu bearbeiten ?? Das ist effizienter und würde Ihnen viel Ärger ersparen

Ich muss auch erwähnen, dass man das beste Tool für den besten Job verwendet ... Was Sie wollen, ist im Grunde eine Funktion einer Datenbank

Grundsätzlich ist es eine praktische Funktion, um Informationen aus PHP-Arrays zu extrahieren. Wenn Sie die Array-Struktur (den ArrayPath) kennen, können Sie Operationen an mehrdimensionalen Array-Daten ausführen, ohne dass mehrere verschachtelte Schleifen erforderlich sind.

Das Beispiel zeigt, wie Sie einen Pfad verwenden, um nach Werten zu suchen, aber Sie sind immer noch darauf angewiesen, das Array in den Speicher zu laden, und Ihre Klasse führt mehrere Rekursionen und Schleifen aus, was nicht so effizient ist wie eine Datenbank .

Ich schätze Architekturtipps, verwandten oder ähnlichen Code, der ein gutes Praxisbeispiel für das schnelle Erstellen von PHP-"if..else"-Ausdrücken sein kann.

Meinst du wirklich, du willst all die hier rein???