sql >> データベース >  >> NoSQL >> MongoDB

goMongoDBのようなクエリ式オブジェクト評価の実装

    はじめに

    PHPでMongoDBのようなJSONクエリを評価することで、必要なすべての情報が得られたと思います。必要なのは、ソリューションを創造的にすることであり、あなたはあなたが望むものを達成します

    アレイ

    次の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できます。 それは、$andのような複合式をサポートするように拡張します および$or

    MongoDBのようなクエリ式オブジェクトは、理解と使用が簡単で、クエリと検索対象のオブジェクトの両方が連想配列であるため、クリーンで自己説明的なコードを記述できます。

    配列をMongoDBに書き込んでみませんか 配列ではなくデータベース??それはより効率的であり、それはあなたに多くのトラブルを救うでしょう

    また、最高の仕事に最高のツールを使用することにも言及する必要があります...必要なのは基本的にデータベースの機能です

    基本的に、php配列から情報を抽出するための便利な機能について話します。配列構造(arrayPath)を知っているので、複数のネストされたループを必要とせずに、多次元配列データに対して操作を実行できます。

    この例は、パスを使用して値を検索する方法を示していますが、配列をメモリにロードし、クラスがデータベースほど効率的ではない複数の再帰ansループを実行することに依存しています。

    アーキテクチャのヒント、関連または類似のコードに感謝します。これは、phpの「if..else」式をその場で構築するための良い実践例かもしれません。

    本当にここにあるものすべてが欲しいという意味ですか???



    1. RedisデータベースTTL

    2. AngularJsアプリを作成するときのJadeまたはハンドルバーの使用は何ですか

    3. Sparkシェルを使用したHBase上のSpark

    4. プレーンな文字列の代わりにObjectIdを使用する利点は何ですか?