MongoDB
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> MongoDB

Triển khai đánh giá đối tượng biểu thức truy vấn giống goMongoDB

Giới thiệu

Tôi nghĩ rằng Đánh giá các truy vấn JSON giống MongoDB trong PHP đã cung cấp tất cả Thông tin bạn cần. tất cả những gì bạn cần là sáng tạo với giải pháp và bạn đạt được điều mình muốn

Mảng

Giả sử chúng ta có json sau được chuyển đổi thành mảng

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

Ví dụ 1

kiểm tra xem key - Different sẽ đơn giản như

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

Đầu ra

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

Ví dụ 2 Kiểm tra xem release year2013

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

Đầu ra

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

Ví dụ 3

Đếm nơi Year2012

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

Ví dụ 4

Hãy lấy ví dụ của bạn nơi bạn muốn kiểm tra version grater than 22

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

Đầu ra

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

Ví dụ 5

Kiểm tra xem release.arch giá trị là IN một tập hợp chẳng hạn như [x86,x100] (Ví dụ)

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

Đầu ra

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
        )

)

Ví dụ 6

Sử dụng có thể gọi được

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

Đầu ra

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

)

Ví dụ 7

Đăng ký tên biểu thức của riêng bạn

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

Đầu ra

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

Lớp được sử dụng

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

Tóm tắt

Nó có thể không bao gồm tất cả các tính năng nâng cao và phải có kiến ​​trúc có thể mở rộng

Lớp trên cho thấy một ví dụ điển hình về những gì bạn muốn .. bạn có thể dễ dàng decouple nó, mở rộng nó để hỗ trợ các biểu thức ghép như $and$or

Các đối tượng biểu thức truy vấn giống MongoDB dễ hiểu và dễ sử dụng, cung cấp khả năng viết mã rõ ràng, tự giải thích vì cả truy vấn và đối tượng cần tìm kiếm đều là các mảng liên kết.

Tại sao không chỉ ghi mảng vào MongoDB cơ sở dữ liệu hơn là làm việc nó mảng ?? Nó hiệu quả hơn và nó sẽ giúp bạn tiết kiệm rất nhiều rắc rối

Tôi cũng phải đề cập đến việc sử dụng công cụ tốt nhất cho công việc tốt nhất ... Điều bạn muốn về cơ bản là một chức năng của Cơ sở dữ liệu

Về cơ bản, nó là một chức năng thuận tiện để trích xuất thông tin từ các mảng php. Biết cấu trúc mảng (arrayPath), nó sẽ cho phép thực hiện các thao tác trên dữ liệu mảng nhiều chiều mà không cần nhiều vòng lặp lồng nhau.

Ví dụ cho thấy cách sử dụng đường dẫn để tìm kiếm giá trị nhưng bạn vẫn phụ thuộc vào việc tải mảng vào bộ nhớ và lớp của bạn thực hiện nhiều vòng lặp ans đệ quy không hiệu quả như cơ sở dữ liệu.

Tôi đánh giá cao các mẹo về kiến ​​trúc, mã liên quan hoặc tương tự, đây có thể là một ví dụ thực tiễn tốt để xây dựng nhanh các biểu thức php "if..else".

Ý bạn thực sự là bạn muốn tất cả những thứ đó chỉ ở đây ???



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Cuộc chiến của các cơ sở dữ liệu NoSQL - So sánh MongoDB và Oracle NoSQL

  2. Mongo chuyển đổi tất cả các trường số được lưu trữ dưới dạng chuỗi

  3. Thuộc tính Mongoengine create_time trong Tài liệu

  4. MongoDB $ sampleRate

  5. ImportError:Không có mô-đun nào có tên objectid