這裡介紹如何在 PHP 中使用 MongoDB 資料庫,包含插入新增、修改更新與刪除資料等各種詳細範例教學。

MongoDB 除了基本的 MongoDB Shell 使用方式之外,它也提供了各種程式語言的 driver,以下我們介紹在 PHP 中的 MongoDB 資料庫使用方式。

本文內容已經過時,可能無法實作。

PHP 使用 MongoDB 基本入門範例

以下是在 PHP 中使用 MongoDB 的範例程式碼:

<?php
// MongoDB 伺服器設定
$dbhost = 'localhost';
$dbname = 'gtwang_demo';

// 連線到 MongoDB 伺服器
$mongoClient = new MongoClient('mongodb://' . $dbhost);
$db = $mongoClient->$dbname;

// 取得 demo 這個 collection
$cDemo = $db->demo;

// 要儲存的資料
$record = array(
  'firstName' => 'G.T.',
  'lastName' => 'Wang',
  'roles' => array('developer', 'webmaster')
);

// 將資料儲存至 demo 這個 collection 中
$cDemo->save($record);

// 設定查詢條件
$queryCondition = array(
  'firstName' => 'G.T.',
  'lastName' => 'Wang'
);

// 查詢資料
$result = $cDemo->findOne($queryCondition);

// 輸出資料
print_r($result);
?>

輸出為

Array
(
    [_id] => MongoId Object
        (
            [$id] => 564e8db0b2fd7fb8278b4567
        )

    [firstName] => G.T.
    [lastName] => Wang
    [roles] => Array
        (
            [0] => developer
            [1] => webmaster
        )

)

這裡用的 save 函數會依據 _id 檢查要儲存的 document 是否已經存在於 MongoDB 中,如果該 document 不存在的話,就會新增一筆,反之如果這個 document 已經存在了,就會更新該 document 資料。

如果只是單純要新增資料,可以使用 insert 函數,更新資料則可用 update 函數。

這時候我們可以使用 MongoDB Shell 連進 MongoDB 資料庫中,檢查一下資料是不是真的有儲存進去,執行:

mongo gtwang_demo
MongoDB shell version: 2.4.9
connecting to: gtwang_demo

進入 MongoDB Shell 後,查看 gtwang_demo 這個 database 中所有的 collection:

show collections
demo
system.indexes

確實有出現新增的 demo collection。(在 MongoDB 中的 system.* 是系統用的 collection,不必理會它)

接著列出裡面的資料,執行:

db.demo.findOne()
{
	"_id" : ObjectId("564e936bb2fd7f962e8b4567"),
	"firstName" : "G.T.",
	"lastName" : "Wang",
	"roles" : [
		"developer",
		"webmaster"
	]
}

看起來結果是正確的。接下來要介紹在 PHP 中 MongoDB 的一些進階查詢方法。

進階查詢

介紹進階查詢的用法之前,我們要先新增一些資料到 MongoDB 資料庫中,我們接續之前的 PHP 範例程式,一次加入多筆資料到 demo 這個 collection 中:

<?php
// 要儲存的資料
$record2 = array(
  'firstName' => 'Abner',
  'lastName' => 'Wang',
  'roles' => array('developer', 'webmaster')
);
$record3 = array(
  'firstName' => 'Horace',
  'lastName' => 'Wang',
  'roles' => array('user')
);
$record4 = array(
  'firstName' => 'Karry',
  'lastName' => 'Li',
  'roles' => array('developer')
);

// 將多筆資料插入 demo 這個 collection 中
$cDemo->batchInsert(
    array($record2, $record3, $record4),
    array('continueOnError' => true)
);
?>

batchInsert 這個 PHP 函數可以用來一次插入多筆 documents 至指定的 collection 中,第一個參數是 documents 的陣列,而第二個參數則是選項的陣列。

之前我們使用的 findOne 只會傳回第一筆符合條件的資料,如果我們需要列出多筆資料時,就要使用 find 函數:

<?php
// 設定查詢條件
$queryCondition = array(
  'lastName' => 'Wang'
);

// 查詢並列出所有符合條件的資料
$cursor = $cDemo->find($queryCondition);
foreach ($cursor as $doc) {
  print_r($doc);
}
?>

這樣就會列出所有符合搜尋條件的資料:

Array
(
    [_id] => MongoId Object
        (
            [$id] => 564e936bb2fd7f962e8b4567
        )

    [firstName] => G.T.
    [lastName] => Wang
    [roles] => Array
        (
            [0] => developer
            [1] => webmaster
        )

)
Array
(
    [_id] => MongoId Object
        (
            [$id] => 564ebc30b2fd7fa2158b4567
        )

    [firstName] => Abner
    [lastName] => Wang
    [roles] => Array
        (
            [0] => developer
            [1] => webmaster
        )

)
Array
(
    [_id] => MongoId Object
        (
            [$id] => 564ebc30b2fd7fa2158b4568
        )

    [firstName] => Horace
    [lastName] => Wang
    [roles] => Array
        (
            [0] => user
        )

)

這是比較複雜的查詢條件,列出 roleswebmasteruser 的人:

<?php
// 設定查詢條件
$queryCondition = array(
  'roles' => array('$in' => array('webmaster', 'user'))
);

// 查詢並列出所有符合條件的資料
$cursor = $cDemo->find($queryCondition);
foreach ($cursor as $doc) {
  print_r($doc);
}
?>

輸出為

Array
(
    [_id] => MongoId Object
        (
            [$id] => 564e936bb2fd7f962e8b4567
        )

    [firstName] => G.T.
    [lastName] => Wang
    [roles] => Array
        (
            [0] => developer
            [1] => webmaster
        )

)
Array
(
    [_id] => MongoId Object
        (
            [$id] => 564ebc30b2fd7fa2158b4567
        )

    [firstName] => Abner
    [lastName] => Wang
    [roles] => Array
        (
            [0] => developer
            [1] => webmaster
        )

)
Array
(
    [_id] => MongoId Object
        (
            [$id] => 564ebc30b2fd7fa2158b4568
        )

    [firstName] => Horace
    [lastName] => Wang
    [roles] => Array
        (
            [0] => user
        )

)

也可以使用 JavaScript 來設定查詢的篩選條件:

<?php
// 使用 JavaScript 設定查詢條件
$js = "function() {
  return this.lastName == 'Li' || this.roles == 'user';
}";
$queryCondition = array('$where' => $js);

// 查詢並列出所有符合條件的資料
$cursor = $cDemo->find($queryCondition);
foreach ($cursor as $doc) {
  print_r($doc);
}
?>

這樣會篩選出 lastNameLirolesuser 的人:

Array
(
    [_id] => MongoId Object
        (
            [$id] => 564ebc30b2fd7fa2158b4568
        )

    [firstName] => Horace
    [lastName] => Wang
    [roles] => Array
        (
            [0] => user
        )

)
Array
(
    [_id] => MongoId Object
        (
            [$id] => 564ebc30b2fd7fa2158b4569
        )

    [firstName] => Karry
    [lastName] => Li
    [roles] => Array
        (
            [0] => developer
        )

)

其餘的範例可參考 find 的網頁。

更新資料

在 MongoDB 的資料更新方法有兩種,一種是更新 document 中部份的資訊,假設 documents 的資料是這樣:

{
  "firstName" : "G.T.",
  "lastName" : "Wang",
  "roles" : [  "developer",  "webmaster" ]
}

更新 email 的資訊:

<?php
$cDemo->update(
  array("firstName" => "G.T.", "lastName" => "Wang"),
  array('$set' => array("email" => "gtw@gtwang.org"))
);
?>

更新之後,會變成這樣:

{
  "firstName" : "G.T.",
  "lastName" : "Wang",
  "roles" : [  "developer",  "webmaster" ],
  "email" : "gtw@gtwang.org"
}

另外一種更新方式是將整筆 document 覆蓋過去,假設 documents 的資料是這樣:

{
  "firstName" : "G.T.",
  "lastName" : "Wang",
  "roles" : [  "developer",  "webmaster" ]
}

使用新的 document 直接蓋掉舊的:

<?php
$cDemo->update(
  array("firstName" => "G.T.", "lastName" => "Wang"),
  array(
    "username" => "gtwang",
    "info" => array("name" => "G. T. Wang", "email" => "gtw@gtwang.org"),
    "likes" => array()
  )
);
?>

更新之後,會變成這樣:

{
  "username" : "gtwang",
  "info" : { "name" : "G. T. Wang", "email" : "gtw@gtwang.org" },
  "likes" : [ ]
}

其他進階的範例請參考 update 的網頁說明文件。

刪除資料

假設我們想要刪除這一筆資料:

{
  "_id" : ObjectId("5650f638b2fd7f7b198b4567"),
  "firstName" : "G.T.",
  "lastName" : "Wang",
  "roles" : [  "developer",  "webmaster" ]
}

可以依據 _id 刪除:

<?php
$id = '5650f638b2fd7f7b198b4567';
$cDemo->remove(array('_id' => new MongoId($id)));
?>

或是使一般的查詢條件來找出這一筆 document 並刪除:

<?php
$cDemo->remove(
  array("firstName" => "G.T.", "lastName" => "Wang")
);
?>

假設資料庫中有很多筆重複的資料時:

{ "_id" : ObjectId("5650fb61b2fd7fd91b8b4567"), "firstName" : "G.T.", "lastName" : "Wang", "roles" : [  "developer",  "webmaster" ] }
{ "_id" : ObjectId("5650fb92b2fd7fec1b8b4567"), "firstName" : "G.T.", "lastName" : "Wang", "roles" : [  "developer",  "webmaster" ] }
{ "_id" : ObjectId("5650fb93b2fd7fee1b8b4567"), "firstName" : "G.T.", "lastName" : "Wang", "roles" : [  "developer",  "webmaster" ] }
{ "_id" : ObjectId("5650fb94b2fd7ff01b8b4567"), "firstName" : "G.T.", "lastName" : "Wang", "roles" : [  "developer",  "webmaster" ] }

我們可以利用這樣的方式把重複的資料刪掉,只留下一筆:

<?php
$condition = array("firstName" => "G.T.", "lastName" => "Wang");

// 計算重複資料筆數
$remaining = $cDemo->count($condition);

// 要刪除的資料筆數
$delete = $remaining - 1;

// 刪除資料
while ($delete > ) {
  $cDemo->remove($condition, array("justOne" => true));
  $delete--;
}
?>

執行完之後,就只會剩下一筆:

{ "_id" : ObjectId("5650fb94b2fd7ff01b8b4567"), "firstName" : "G.T.", "lastName" : "Wang", "roles" : [  "developer",  "webmaster" ] }

刪除 Collection

如果要在 PHP 中刪除 MongoDB 資料數的 collection,可以使用 drop

<?php
$response = $cDemo->drop();
print_r($response);
?>

刪除後,會傳回類似這樣的資訊:

Array
(
    [nIndexesWas] => 1
    [msg] => indexes dropped for collection
    [ns] => gtwang_demo.demo
    [ok] => 1
)

計算 Documents 數量

如果要計算 collection 中所有的 documents 數量可以使用 count

<?php
$count = $cDemo->count();
?>

我們也可以加入查詢條件,計算符合條件的 documents 數目:

<?php
$count = $cDemo->count(
  array("firstName" => "G.T.", "lastName" => "Wang")
);
?>

更新 document 並傳回

如果要更新一筆 document,並且取得更新後的資料,可以使用 findAndModify

<?php
$retval = $cDemo->findAndModify(
  array("firstName" => "G.T.", "lastName" => "Wang"),
  array('$set' => array("email" => "gtw@gtwang.org")),
  null,
  array("new" => true)
);

print_r($retval);
?>

輸出為:

Array
(
    [_id] => MongoId Object
        (
            [$id] => 565107cab2fd7f1d228b4567
        )

    [email] => gtw@gtwang.org
    [firstName] => G.T.
    [lastName] => Wang
    [roles] => Array
        (
            [0] => developer
            [1] => webmaster
        )

)

圖片來源:Garrett Heath