ZetCode

MongoDB PHP

最后修改于 2020 年 7 月 6 日

在本教程中,我们将展示如何在 PHP 中使用 MongoDB。我们使用新的 mongodb PHP 驱动。ZetCode 上有一个简洁的 PHP 教程

MongoDB 是一个 NoSQL 跨平台面向文档的数据库。它是目前最流行的数据库之一。MongoDB 由 MongoDB Inc. 开发,并作为免费和开源软件发布。

MongoDB 中的一条记录就是一个文档,它是一个由字段和值对组成的数据结构。MongoDB 的文档类似于 JSON 对象。字段的值可以包括其他文档、数组和文档数组。MongoDB 将文档存储在集合中。集合类似于关系数据库中的表,而文档类似于行。

安装 MongoDB

以下命令可用于在基于 Debian 的 Linux 上安装 MongoDB。

$ sudo apt-get install mongodb

该命令安装 MongoDB 附带的必要软件包。

$ sudo service mongodb status
mongodb start/running, process 975

使用 sudo service mongodb status 命令,我们检查 mongodb 服务器的状态。

$ sudo service mongodb start
mongodb start/running, process 6448

mongodb 服务器通过 sudo service mongodb start 命令启动。

创建数据库

mongo 工具是一个与 MongoDB 交互的 JavaScript shell 界面,它为系统管理员提供了一个接口,也为开发人员提供了一种直接与数据库测试查询和操作的方式。

$ mongo testdb
MongoDB shell version: 2.4.9
connecting to: testdb
> db
testdb
> db.cars.insert({name: "Audi", price: 52642})
> db.cars.insert({name: "Mercedes", price: 57127})
> db.cars.insert({name: "Skoda", price: 9000})
> db.cars.insert({name: "Volvo", price: 29000})
> db.cars.insert({name: "Bentley", price: 350000})
> db.cars.insert({name: "Citroen", price: 21000})
> db.cars.insert({name: "Hummer", price: 41400})
> db.cars.insert({name: "Volkswagen", price: 21600})

我们创建一个 testdb 数据库,并在 cars 集合中插入八个文档。

安装 PHP 驱动

有两个可用的驱动:旧的 mongo 驱动和新的 mongodb 驱动。在本教程中,我们使用新的 mongodb 驱动。

接下来,我们展示如何手动安装 PHP MongoDB 驱动。

$ git clone https://github.com/mongodb/mongo-php-driver.git
$ cd mongo-php-driver
$ git submodule sync && git submodule update --init
$ phpize
$ ./configure
$ make 
$ sudo make install

我们下载源代码并从中安装驱动。

extension=mongodb.so

我们将 mongodb.so 扩展添加到 php.ini 文件中。

数据库统计信息

第一个示例连接到 testdb 数据库并获取其统计信息。

MongoDB\Driver\Manager 负责维护与 MongoDB 的连接。MongoDB\Driver\Command 代表一个数据库命令。成功时,该命令返回 MongoDB\Driver\Cursor

dbstats.php
<?php

try {

    $mng = new MongoDB\Driver\Manager("mongodb://:27017");

    $stats = new MongoDB\Driver\Command(["dbstats" => 1]);
    $res = $mng->executeCommand("testdb", $stats);
    
    $stats = current($res->toArray());

    print_r($stats);

} catch (MongoDB\Driver\Exception\Exception $e) {

    $filename = basename(__FILE__);
    
    echo "The $filename script has experienced an error.\n"; 
    echo "It failed with the following exception:\n";
    
    echo "Exception:", $e->getMessage(), "\n";
    echo "In file:", $e->getFile(), "\n";
    echo "On line:", $e->getLine(), "\n";       
}
    
?>

该示例连接到 testdb 数据库并执行 dbstats 命令。它显示了一些数据库统计信息。

$mng = new MongoDB\Driver\Manager("mongodb://:27017");

我们使用 MongoDB\Driver\Manager 类连接到 testdb 数据库。27017 是 MongoDB 服务器监听的默认端口。

$res = $mng->executeCommand("testdb", $stats);

MongoDB\Driver\Command 用于执行 dbstats 命令。

$stats = current($res->toArray());

toArray 方法返回一个包含此游标所有结果的数组,而 current 函数返回数组的当前元素。在我们的例子中,数组只有一个元素。

print_r($stats);

print_r 函数以人类可读的格式打印 $stats 变量。

$ php dbstats.php 
stdClass Object
(
    [db] => testdb
    [collections] => 3
    [objects] => 12
    [avgObjSize] => 52.666666666667
    [dataSize] => 632
    [storageSize] => 12288
    [numExtents] => 3
    [indexes] => 1
    [indexSize] => 8176
    [fileSize] => 201326592
    [nsSizeMB] => 16
    [dataFileVersion] => stdClass Object
        (
            [major] => 4
            [minor] => 5
        )

    [ok] => 1
)

这是 dbstats.php 程序的输出。

列出数据库

listDatabases 命令提供所有现有数据库的列表。

list_databases.php
<?php

try {

    $mng = new MongoDB\Driver\Manager("mongodb://:27017");

    $listdatabases = new MongoDB\Driver\Command(["listDatabases" => 1]);
    $res = $mng->executeCommand("admin", $listdatabases);

    $databases = current($res->toArray());

    foreach ($databases->databases as $el) {
    
        echo $el->name . "\n";
    }

} catch (MongoDB\Driver\Exception\Exception $e) {

    $filename = basename(__FILE__);
    
    echo "The $filename script has experienced an error.\n"; 
    echo "It failed with the following exception:\n";
    
    echo "Exception:", $e->getMessage(), "\n";
    echo "In file:", $e->getFile(), "\n";
    echo "On line:", $e->getLine(), "\n";       
}

?>

该示例打印出 MongoDB 中可用的数据库。

$listdatabases = new MongoDB\Driver\Command(["listDatabases" => 1]);
$res = $mng->executeCommand("admin", $listdatabases);

我们执行 listDatabases 命令。该命令在 admin 数据库上执行。

$databases = current($res->toArray());

该命令返回一个结果文档,其中包含 databases 数组字段中所有数据库的信息。

foreach ($databases->databases as $el) {

    echo $el->name . "\n";
}

我们遍历 databases 数组并打印可用数据库的名称。

$ php list_databases.php 
testdb
test
local

在我们的本地机器上,有这三个数据库。

读取数据

MongoDB\Driver\Query 是一个表示数据库查询的值对象。

read_all.php
<?php

try {

    $mng = new MongoDB\Driver\Manager("mongodb://:27017");
    $query = new MongoDB\Driver\Query([]); 
     
    $rows = $mng->executeQuery("testdb.cars", $query);
    
    foreach ($rows as $row) {
    
        echo "$row->name : $row->price\n";
    }
    
} catch (MongoDB\Driver\Exception\Exception $e) {

    $filename = basename(__FILE__);
    
    echo "The $filename script has experienced an error.\n"; 
    echo "It failed with the following exception:\n";
    
    echo "Exception:", $e->getMessage(), "\n";
    echo "In file:", $e->getFile(), "\n";
    echo "On line:", $e->getLine(), "\n";       
}

?>

该示例从 testdb.cars 集合中读取所有数据。

$query = new MongoDB\Driver\Query([]); 

创建了一个 MongoDB\Driver\Query 对象。如果我们传递一个空数组,它会读取所有数据。

$rows = $mng->executeQuery("testdb.cars", $query);

executeQuery 执行查询。第一个参数是集合名称,第二个参数是查询。

foreach ($rows as $row) {

    echo "$row->name : $row->price\n";
}

我们遍历所有匹配的文档。

$ php read_all.php 
Audi : 52642
Mercedes : 57127
Skoda : 9000
Volvo : 29000
Bentley : 350000
Citroen : 21000
Hummer : 41400
Volkswagen : 21600

这是 read_all.php 脚本的输出。

筛选数据

MongoDB\Driver\Query 包含一个用于筛选数据的 filter 参数。

filtering.php
<?php

try {
         
    $mng = new MongoDB\Driver\Manager("mongodb://:27017");
    
    $filter = [ 'name' => 'Volkswagen' ]; 
    $query = new MongoDB\Driver\Query($filter);     
    
    $res = $mng->executeQuery("testdb.cars", $query);
    
    $car = current($res->toArray());
    
    if (!empty($car)) {
    
        echo $car->name, ": ", $car->price, PHP_EOL;
    } else {
    
        echo "No match found\n";
    }
    
} catch (MongoDB\Driver\Exception\Exception $e) {

    $filename = basename(__FILE__);
    
    echo "The $filename script has experienced an error.\n"; 
    echo "It failed with the following exception:\n";
    
    echo "Exception:", $e->getMessage(), "\n";
    echo "In file:", $e->getFile(), "\n";
    echo "On line:", $e->getLine(), "\n";    
}

?>

该示例搜索一辆大众汽车的价格。

$filter = [ 'name' => 'Volkswagen' ]; 
$query = new MongoDB\Driver\Query($filter); 

我们向 MongoDB\Driver\Query 提供 filter 参数。

$car = current($res->toArray());

if (!empty($car)) {

    echo $car->name, ": ", $car->price, PHP_EOL;
} else {

    echo "No match found\n";
}

我们打印所选汽车的名称和价格。我们使用 empty 函数确保返回的变量不为空。

$ php filtering.php 
Volkswagen: 21600

这是 filtering.php 脚本的输出。

投影 (Projections)

投影可用于指定应返回哪些字段。

projection.php
<?php

try {
     
    $filter = [];
    $options = ["projection" => ['_id' => 0]];
    
    $mng = new MongoDB\Driver\Manager("mongodb://:27017");
    $query = new MongoDB\Driver\Query($filter, $options);
    
    $rows = $mng->executeQuery("testdb.cars", $query);
       
    foreach ($rows as $row) {
          
           print_r($row);
    }    
        
} catch (MongoDB\Driver\Exception\Exception $e) {

    $filename = basename(__FILE__);
    
    echo "The $filename script has experienced an error.\n"; 
    echo "It failed with the following exception:\n";
    
    echo "Exception:", $e->getMessage(), "\n";
    echo "In file:", $e->getFile(), "\n";
    echo "On line:", $e->getLine(), "\n";    
}

?>

在此示例中,我们隐藏了第一个字段——_id

$options = ["projection" => ['_id' => 0]];

投影在 projection 数组中指定。这里我们隐藏 _id 字段。

$query = new MongoDB\Driver\Query($filter, $options);     

投影作为 MongoDB\Driver\Query 的第二个参数传递。

$ php projection.php 
stdClass Object
(
    [name] => Audi
    [price] => 52642
)
stdClass Object
(
    [name] => Mercedes
    [price] => 57127
)
...

这是 projection.php 脚本的部分输出。只返回了 name 和 price 字段。

限制数据输出

limit 查询选项指定要返回的文档数量,而 sort 选项指定排序顺序。

read_limit.php
<?php

try {
     
    $mng = new MongoDB\Driver\Manager("mongodb://:27017");
    $query = new MongoDB\Driver\Query([], ['sort' => [ 'name' => 1], 'limit' => 5]);     
    
    $rows = $mng->executeQuery("testdb.cars", $query);
    
    foreach ($rows as $row) {
    
        echo "$row->name : $row->price\n";
    }
    
} catch (MongoDB\Driver\Exception\Exception $e) {

    $filename = basename(__FILE__);
    
    echo "The $filename script has experienced an error.\n"; 
    echo "It failed with the following exception:\n";
    
    echo "Exception:", $e->getMessage(), "\n";
    echo "In file:", $e->getFile(), "\n";
    echo "On line:", $e->getLine(), "\n";       
}

?>

该示例从 testdb.cars 集合中读取所有数据,将输出限制为五辆车,并按车名升序排序。

$query = new MongoDB\Driver\Query([], ['sort' => [ 'name' => 1], 'limit' => 5]); 

我们在查询的第二个参数中指定 sortlimit 选项。

$ php read_limit.php 
Audi : 52642
Bentley : 350000
Citroen : 21000
Hummer : 41400
Mercedes : 57127

这是 read_limit.php 脚本的输出。

批量写入

MongoDB\Driver\Manager::executeBulkWrite 方法执行一个或多个写入操作,包括插入、更新和删除。

bulkwrite.php
<?php

try {
     
    $mng = new MongoDB\Driver\Manager("mongodb://:27017");
    
    $bulk = new MongoDB\Driver\BulkWrite;
    
    $doc = ['_id' => new MongoDB\BSON\ObjectID, 'name' => 'Toyota', 'price' => 26700];
    $bulk->insert($doc);
    $bulk->update(['name' => 'Audi'], ['$set' => ['price' => 52000]]);
    $bulk->delete(['name' => 'Hummer']);
    
    $mng->executeBulkWrite('testdb.cars', $bulk);
        
} catch (MongoDB\Driver\Exception\Exception $e) {

    $filename = basename(__FILE__);
    
    echo "The $filename script has experienced an error.\n"; 
    echo "It failed with the following exception:\n";
    
    echo "Exception:", $e->getMessage(), "\n";
    echo "In file:", $e->getFile(), "\n";
    echo "On line:", $e->getLine(), "\n";    
}

?>

该脚本插入一辆新车,更新一辆车,并删除一辆车。

$bulk = new MongoDB\Driver\BulkWrite();

MongoDB\Driver\BulkWrite 收集一个或多个应发送到服务器的写入操作。

$doc = ['_id' => new MongoDB\BSON\ObjectID, 'name' => 'Toyota', 'price' => 26700];

这是一个要插入的新文档。MongoDB\BSON\ObjectID 生成一个新的 ObjectId。它是一个用于唯一标识集合中文档的值。

$bulk->insert($doc);

使用 insert 方法创建一个插入操作。

$bulk->update(['name' => 'Audi'], ['$set' => ['price' => 52000]]);

使用 update 方法创建一个更新操作。$set 操作符用指定的值替换字段的值。

$bulk->delete(['name' => 'Hummer']);

使用 delete 方法创建一个删除操作。

$mng->executeBulkWrite('testdb.cars', $bulk);

executeBulkWritetestdb.cars 集合上执行这三个操作。

> db.cars.find()
{ "_id" : ObjectId("571e05a6c4a3bc7dc758b457"), "name" : "Audi", "price" : 52000 }
{ "_id" : ObjectId("571e05b5c4a3bc7dc758b458"), "name" : "Mercedes", "price" : 57127 }
{ "_id" : ObjectId("571e05bec4a3bc7dc758b459"), "name" : "Skoda", "price" : 9000 }
{ "_id" : ObjectId("571e05c7c4a3bc7dc758b45a"), "name" : "Volvo", "price" : 29000 }
{ "_id" : ObjectId("571e05d0c4a3bc7dc758b45b"), "name" : "Bentley", "price" : 350000 }
{ "_id" : ObjectId("571e05e0c4a3bc7dc758b45c"), "name" : "Citroen", "price" : 21000 }
{ "_id" : ObjectId("571e05fcc4a3bc7dc758b45e"), "name" : "Volkswagen", "price" : 21600 }
{ "_id" : ObjectId("5720a4e581365b0e9414d0e1"), "name" : "Toyota", "price" : 26700 }

我们使用 mongo 工具确认更改。

在本教程中,我们学习了如何使用 MongoDB 和 PHP。