MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Implementacja oceny obiektu wyrażenia zapytania podobnego do goMongoDB

Wprowadzenie

Myślę, że ocena zapytań JSON podobnych do MongoDB w PHP dała wszystkie potrzebne informacje. wszystko, czego potrzebujesz, to kreatywność z rozwiązaniem i osiągnięcie tego, czego chcesz

Tablica

Załóżmy, że mamy następujący json konwertowane na tablicę

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

Przykład 1

sprawdź, czy key - Different byłoby tak proste jak

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

Wyjście

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

Przykład 2 Sprawdź, czy release year jest 2013

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

Wyjście

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

Przykład 3

Policz gdzie Year jest 2012

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

Przykład 4

Weźmy z twojego przykładu, gdzie chcesz sprawdzić version jest grater than 22

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

Wyjście

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

Przykład 5

Sprawdź, czy release.arch wartość to IN zestaw taki jak [x86,x100] (Przykład)

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

Wyjście

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
        )

)

Przykład 6

Korzystanie z opcji wywoływania

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

Wyjście

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

)

Przykład 7

Zarejestruj własną nazwę wyrażenia

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

Wyjście

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

Używana klasa

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

Podsumowanie

Może nie obejmować wszystkich zaawansowanych funkcji i powinien mieć rozszerzalną architekturę

Powyższa klasa pokazuje typowy przykład tego, czego chcesz .. możesz łatwo decouple it , rozszerz go o obsługę wyrażeń złożonych, takich jak $and i $or

Obiekty wyrażeń zapytań podobne do MongoDB są łatwe do zrozumienia i użycia, zapewniając możliwość pisania czystego, zrozumiałego kodu, ponieważ zarówno zapytania, jak i obiekty do przeszukiwania są tablicami asocjacyjnymi.

Dlaczego nie po prostu napisać tablicy do MongoDB? bazy danych zamiast pracy z tablicami ?? Jest bardziej wydajny i zaoszczędzi ci wielu kłopotów

Muszę również wspomnieć, że używaj najlepszego narzędzia do najlepszej pracy ... To, czego potrzebujesz, to w zasadzie funkcja bazy danych

Mówiąc ogólnie, jest to wygodna funkcja do wyodrębniania informacji z tablic php. Znając strukturę tablicy (arrayPath), pozwoli to na wykonywanie operacji na wielowymiarowych danych tablicowych, bez potrzeby wielu zagnieżdżonych pętli.

Przykład pokazuje, jak używać ścieżki do wyszukiwania wartości, ale nadal jesteś zależny od załadowania tablicy do pamięci i twojej klasy wykonującej wielokrotną rekurencję i pętle, co nie jest tak wydajne jak baza danych.

Doceniam wskazówki dotyczące architektury, pokrewny lub podobny kod, który może być dobrym przykładem praktyki tworzenia wyrażeń php "if..else" w locie.

Czy naprawdę masz na myśli, że chcesz, aby wszystkie te były tutaj ???



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Wszystko, co musisz wiedzieć o kliencie MongoDB

  2. MongoDB — Błąd:polecenie getMore nie powiodło się:nie znaleziono kursora

  3. MongoDB - kopiuj kolekcję w Javie bez zapętlania wszystkich elementów

  4. Zaktualizować obiekt tablicy na podstawie identyfikatora?

  5. ImportError:Brak modułu o nazwie objectid