MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Внедряване на оценка на обекта на израз на заявка, подобна на goMongoDB

Въведение

Мисля, че оценяването на подобни на MongoDB JSON заявки в PHP е дало цялата информация, от която се нуждаете. всичко, от което се нуждаете, е да бъдете креативни с решението и ще постигнете това, което искате

Масивът

Да предположим, че имаме следния json преобразува се в масив

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

Пример 1

проверете дали key - Different би било толкова просто, колкото

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

Изход

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

Пример 2 Проверете дали release year е 2013

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

Изход

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

Пример 3

Бройте къде Year е 2012

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

Пример 4

Нека вземем от вашия пример, където искате да проверите version е grater than 22

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

Изход

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

Пример 5

Проверете дали release.arch стойността е IN набор като [x86,x100] (Пример)

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

Изход

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
        )

)

Пример 6

Използване на 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);
}

Изход

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

)

Пример 7

Регистрирайте собственото си име на израз

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

Изход

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

Клас Използван

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

Резюме

Може да не покрива всички разширени функции и трябва да има разширяема архитектура

Горният клас показва типичен пример за това, което искате .. можете лесно да decouple it , разширете го, за да поддържате съставни изрази като $and и $or

Подобни на MongoDB обекти за израз на заявка са лесни за разбиране и използване, като осигуряват възможност за писане на чист, самообясняващ се код, тъй като и заявката, и обектите за търсене са асоциативни масиви.

Защо просто не напишете масива в MongoDB база данни, вместо да я работи с масиви?? Това е по-ефективно и ще ви спести много проблеми

Трябва също да спомена, че използвайте най-добрия инструмент за най-добрата работа ... Това, което искате, е основно функция на база данни

По принцип това е удобна функция за извличане на информация от php масиви. Познавайки структурата на масива (arrayPath), това ще позволи да се извършват операции върху многомерни масиви от данни, без да са необходими множество вложени цикли.

Примерът показва как използвате път за търсене на стойност, но все още сте зависими от зареждането на масива в паметта и вашият клас изпълнява множество рекурсия и цикли, което не е толкова ефективно като база данни.

Оценявам съветите за архитектура, свързан или подобен код, който може да бъде пример за добра практика за изграждане на php „if..else“ изрази в движение.

Наистина ли искаш да кажеш, че искаш всички тези просто тук ???



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Заявка за диапазон за пагинация на MongoDB

  2. Преглед на валидирането на схемата на MongoDB

  3. mongodb/mongoose findMany - намерете всички документи с идентификатори, изброени в масив

  4. Как да заредя 100 милиона записа в MongoDB със Scala за тестване на производителността?

  5. Как мога да направя заявка за mongodb с помощта на mongoid/rails без изтичане на времето?