Контакты
email:
skype:
© 2008 – 2021
» » mongodb

Новый драйвер mongodb для PHP - черновик по основным запросам


Ранее писал черновик по основным запросам Mongodb в PHP, но стоило обновить пхп, и каково было мое разочарование, новый драйвер php для mongo полностью поменял синтаксис.
Это хорошо, что не стоит на месте, и плохо, что придется переписывать. На данный момент (написания статьи, а не ее публикации) нет ни одной odm и orm поддерживающей новый драйвер. Только библиотека которая является оберткой для драйвера, и какой-то не полной (http://mongodb.github.io/mongo-php-library/api/index.html)

Вот наш герой: https://github.com/mongodb/mongo-php-driver
pecl/mongodb это новый MongoDB driver для PHP, а раньше это был его наследник pecl/mongo driver.

Что же делать и как дальше быть, попытаемся разобраться.
Документация http://php.net/manual/ru/set.mongodb.php
Поехали:
<?php
// INIT
$mongo = new MongoDB\Driver\Manager("mongodb://localhost:27017");


// INSERT
$document = ["hello" => "world"];
$bulk = new MongoDB\Driver\BulkWrite;
$id = $bulk->insert($document);
try {
    $result = $mongo->executeBulkWrite('mydb.collection', $bulk);
    echo (string)$id;
} catch (MongoDB\Driver\Exception\Exception $e) {
    echo $e->getMessage(), "\n";
}


// SELECT
$filter = [
    'hello' => 'world'
];
$options = [
    'projection' => [
        'hello' => 1,
    ],
    'sort' => [
        "hello" => -1,
    ],
    'skip' => 2,
    'limit' => 5
];
$query = new MongoDB\Driver\Query($filter, $options);
try {
    $cursor = $mongo->executeQuery('mydb.collection', $query);
    // здесь тоже можно посчитать количество с помощью iterator_count($cursor)
    // если хотите работать как с массивом а не обьектом, то приходится преобразовывать =(
    $cursor = MongoDB\BSON\fromPHP($cursor->toArray());
    $cursor = json_decode(MongoDB\BSON\toJSON($cursor), true);
    //
} catch (MongoDB\Driver\Exception\Exception $e) {
    echo $e->getMessage(), "\n";
}
foreach($cursor as $document) {
    echo "<pre>";
    print_r($document);
    echo "</pre>";
}
// count считаем так или смотрите ниже выполнение count c помощью Command
$count = count($cursor); */


// SELECT_ONE
// аналогично // SELECT только limit указуем в 1


// UPDATE
$filter = ["hello" => "world"];
$update = ['$set' => ["hello" => "wonderful world"]];
$options = ["limit" => 1, "upsert" => false];
$bulk = new MongoDB\Driver\BulkWrite;
$bulk->update($filter, $update, $options);
try {
    $result = $mongo->executeBulkWrite('mydb.collection', $bulk);
    var_dump($result);
} catch (MongoDB\Driver\Exception\Exception $e) {
    echo $e->getMessage(), "\n";
}


// DELETE
$filter = ['hello' => 'world'];
$options = ["limit" => 1];
$bulk = new MongoDB\Driver\BulkWrite;
$bulk->delete($filter, $options);
try {
    $result = $mongo->executeBulkWrite('mydb.collection', $bulk);
    var_dump($result);
} catch (MongoDB\Driver\Exception\Exception $e) {
    echo $e->getMessage(), "\n";
}


// ВЫПОЛНЕНИЕ ЗАПРОСОВ С ПОМОЩЬЮ  КОМАНД - COUNT и COMPLEX SELECT

// COUNT пример считаем количество записей world
$query = ["hello" => "world"];
$command = new MongoDB\Driver\Command(["count" => "collection", "query" => $query]);
try {
    $result = $mongo->executeCommand("mydb", $command);
    $res = current($result->toArray());
    $count = $res->n;
    echo $count;
} catch (MongoDB\Driver\Exception\Exception $e) {
    echo $e->getMessage(), "\n";
}


// COMPLEX SELECT (это пример, результат этого запроса будет пустой)
$command = new MongoDB\Driver\Command([
    'aggregate' => 'collection',
    'pipeline' => [
        ['$match' => [
            "hello" => "world"
        ]],
        ['$project' => [
            "hello" => 1
        ]],
        ['$group' => [
            '_id' => '$hello', 'sum' => ['$sum' => '$world']
        ]],
        ['$skip' => 1],
        ['$limit' => 1],
        ['$sort' => [
            'hello' => 1
        ]],
    ],
    'cursor' => new stdClass,
]);
$cursor = $mongo->executeCommand('mydb', $command);
foreach ($cursor as $document) {
    echo "<pre>";
    var_dump($document);
    echo "</pre>";
}


//еще хотелось бы показать нюансы вставки и преобразования дат 

// ВСТАВИТЬ ТЕКУЩУЮ ДАТУ
$milliseconds = round(microtime(true) * 1000); // теперь это миллисекунды
$document = ["date" => new MongoDB\BSON\UTCDateTime($milliseconds)];
$bulk = new MongoDB\Driver\BulkWrite;
$id = $bulk->insert($document);
try {
    $result = $mongo->executeBulkWrite('mydb.collection', $bulk);
    echo (string)$id;
} catch (MongoDB\Driver\Exception\Exception $e) {
    echo $e->getMessage(), "\n";
}


// ИЗВЛЕКАЕМ ДАТУ И ДЕЛАЕМ ЧИТАБЕЛЬНОЙ
// раньше был new Mongoid($_id)
// теперь это new MongoDB\BSON\ObjectId($_id)
$filter = ['_id' => new MongoDB\BSON\ObjectId('568991464c20200df6792a39')];
$options = ['limit' => 1];
$query = new MongoDB\Driver\Query($filter, $options);
try {
    $cursor = $mongo->executeQuery('mydb.collection', $query);
    // если хотите работать как с массивом а не обьектом, то приходится преобразовывать =(
    $cursor = MongoDB\BSON\fromPHP($cursor->toArray());
    $cursor = json_decode(MongoDB\BSON\toJSON($cursor), true);
    //
} catch (MongoDB\Driver\Exception\Exception $e) {
    echo $e->getMessage(), "\n";
}
$res = current($cursor);
// можно так
$date = date('Y-m-d H:m:s', $res['date']['$date'] / 1000 );
echo $date.'<br/>';
// можно так
$d = new MongoDB\BSON\UTCDateTime($res['date']['$date']);
$datetime = $d->toDateTime();
$date = $datetime->format('Y-m-d H:m:s');
echo $date.'<br/>';


// Автоинкремент поля Mongodb через findAndModify
// http://veselov.sumy.ua/1960-avtoinkrement-polya-mongodb-na-php.html
$command = new MongoDB\Driver\Command([
    'findAndModify' => 'collection_counters', 
    'query' => ['field' => 'user_id'],
    'update' => ['$inc' => ['nextId' => 1]],
    "new" => true
]);
try {
    $result = $mongo->executeCommand("mydb", $command);
    $num = $result->toArray();
    $num = $num['nextId'];
    // дальше добавляем сам документ
    // ..
} catch (MongoDB\Driver\Exception\Exception $e) {
    echo $e->getMessage(), "\n";
}

 
// Множественный INSERT batchInsert как и UPDATE и DELETE 
// выполняется аналогично insert
$bulk = new MongoDB\Driver\BulkWrite;
$bulk->insert(["hello" => "world"]);
$bulk->insert(["hello1" => "world1"]);
$bulk->insert(["hello2" => "world3"]);
try {
    $result = $mongo->executeBulkWrite('mydb.collection', $bulk);
} catch (MongoDB\Driver\Exception\Exception $e) {
    echo $e->getMessage(), "\n";
}

// преобразование даты для выборки по дате 
// ранее было new MongoDate( time() )
// теперь new MongoDB\BSON\UTCDateTime(  time() * 1000 )
$dateTime = new MongoDB\BSON\UTCDateTime(strtotime(date('Y-m-d H:m:s', time())).'000');
$filter = [
    'date' => [
        '$gte' => new MongoDB\BSON\UTCDateTime(strtotime("{$year}-{$month}-01").'000'),
        '$lt' => new MongoDB\BSON\UTCDateTime(strtotime(date('Y-m-d H:m:s')).'000')
    ]
];


// Было
// new MongoRegex("/$text/i"))
// стало
// new MongoDB\BSON\Regex($text, 'i'))


// И еще пример для размышления =)
$filter = [];
$options = [];
$query = new MongoDB\Driver\Query($filter, $options);
$cursor = $mongo->executeQuery( 'mydb.collection', $query);
$cursor->setTypeMap(['root' => 'array']); // выводим как массив
// формируем массив в нужном для нас порядке
foreach ( $cursor as $doc ) {
    $id = (string)$doc['_id'];
    $res[$id] = $doc;
    unset($res[$id]['_id']);
}
echo "<pre>";
print_r($res);
echo "</pre>";

echo '<br/>ok';

Ну вот вроде как и разобрались с основным представлением о том как выглядит новый php mongodb driver.

Автоинкремент поля Mongodb на PHP


Способ 1 когда документы коллекции только добавляются и не удаляются:
Перед вставкой считаем количество документов и добавляем единицу
$data_insert['num'] = $collection->count()+1;
$collection->insert($data_insert);
То есть всегда получаем количество документов +1. Если в таком случае удалить запись то счетчик собьется и нумерация нарушится. Поэтому используйте в том случаее когда документы не удаляются.

Способ 2 когда документы коллекции удаляются:
Создается отдельная коллекция со счетчиками и вот таким документом к примеру
$data_insert = array(
        'field' => 'user_id',
        'nextId' => 0
);
$collection = $db->selectCollection('counters');
$collection->insert($data_insert);

После чего добавление новых документов выглядит таким образом
$collection = $db->selectCollection('counters');
$retval = $collection->findAndModify(
        array('field' => 'user_id'),
        array('$inc' => array("nextId" => 1)),
        null,
        array(
                "new" => true,
        )
);
$num = $retval['nextId'];
Здесь мы добавили 1 для нашего счетчика, теперь добавляется сам документ
$collection = $db->selectCollection('users');
$data_insert['num'] = $num;
$collection->insert($data_insert);

Создасться запись с полем num = 1, следующая num = 2 и тд.

Теперь когда удалится документ, счетчик не собьется, а продолжит работать и добавлять 1 при добавлении.
Вверх