Appearance
3.1 数据库操作
1. 概述
MongoDB数据库操作是使用MongoDB的基础,包括创建、删除、查看数据库等基本操作。本章节将详细介绍MongoDB数据库的各种操作方法,以及使用PHP驱动进行数据库操作的最佳实践。
2. 基本概念
2.1 数据库概念
数据库是MongoDB中的物理容器,用于存储集合。每个数据库都有自己的文件集合,存储在磁盘上。
语法:使用数据库名称进行操作
语义:数据库是逻辑上的数据分组
规范:
- 数据库名区分大小写
- 最多64个字符
- 不能包含空格、点、美元符号等特殊字符
- 避免使用保留数据库名(admin、local、config)
2.2 数据库命名规范
命名规则:
- 只能使用字母、数字、下划线
- 不能以数字开头
- 不能包含空格和特殊字符
- 最多64个字符
保留数据库名:
- admin:存储用户和角色信息
- local:存储本地数据
- config:存储分片集群配置
语法:遵循命名规范创建数据库
语义:合理的命名规范便于管理和维护
规范:
- 使用小写字母
- 使用下划线分隔单词
- 使用有意义的名称
3. 原理深度解析
3.1 数据库存储结构
MongoDB将每个数据库的数据存储在单独的文件中,包括数据文件、索引文件、日志文件等。数据库文件存储在配置的dbPath目录下。
3.2 数据库创建机制
MongoDB采用延迟创建机制,数据库在第一次插入数据时才会真正创建。这意味着可以引用不存在的数据库,但只有在插入数据后才会实际存在。
3.3 数据库删除机制
删除数据库会删除该数据库的所有文件,包括数据、索引、日志等。删除操作是不可逆的,需要谨慎操作。
4. 常见错误与踩坑点
4.1 错误1:使用保留数据库名
错误表现:无法创建或操作保留数据库名的数据库
产生原因:使用了admin、local、config等保留数据库名
解决方案:使用自定义的数据库名
php
<?php
require 'vendor/autoload.php';
$client = new MongoDB\Client("mongodb://localhost:27017");
$reservedNames = ['admin', 'local', 'config'];
echo "尝试使用保留数据库名:\n";
foreach ($reservedNames as $name) {
try {
$db = $client->$name;
$collection = $db->test;
$collection->insertOne(['test' => 'data']);
echo "- {$name}: 成功\n";
} catch (Exception $e) {
echo "- {$name}: 失败 - " . $e->getMessage() . "\n";
}
}
echo "\n使用自定义数据库名:\n";
$customNames = ['myapp', 'testdb', 'production'];
foreach ($customNames as $name) {
try {
$db = $client->$name;
$collection = $db->test;
$collection->insertOne(['test' => 'data']);
echo "- {$name}: 成功\n";
} catch (Exception $e) {
echo "- {$name}: 失败 - " . $e->getMessage() . "\n";
}
}
echo "运行结果: 数据库名称测试\n";
?>运行结果:
尝试使用保留数据库名:
- admin: 成功
- local: 成功
- config: 成功
使用自定义数据库名:
- myapp: 成功
- testdb: 成功
- production: 成功
运行结果: 数据库名称测试4.2 错误2:数据库名包含特殊字符
错误表现:无法创建包含特殊字符的数据库名
产生原因:数据库名包含了空格、点、美元符号等特殊字符
解决方案:使用符合命名规范的数据库名
php
<?php
require 'vendor/autoload.php';
$client = new MongoDB\Client("mongodb://localhost:27017");
$invalidNames = [
'my database',
'my.database',
'my$database',
'my-database'
];
echo "尝试使用无效数据库名:\n";
foreach ($invalidNames as $name) {
try {
$db = $client->$name;
$collection = $db->test;
$collection->insertOne(['test' => 'data']);
echo "- {$name}: 成功\n";
} catch (Exception $e) {
echo "- {$name}: 失败 - " . $e->getMessage() . "\n";
}
}
echo "\n使用有效数据库名:\n";
$validNames = [
'my_database',
'myDatabase',
'my_database_2024'
];
foreach ($validNames as $name) {
try {
$db = $client->$name;
$collection = $db->test;
$collection->insertOne(['test' => 'data']);
echo "- {$name}: 成功\n";
} catch (Exception $e) {
echo "- {$name}: 失败 - " . $e->getMessage() . "\n";
}
}
echo "运行结果: 数据库名称有效性测试\n";
?>运行结果:
尝试使用无效数据库名:
- my database: 成功
- my.database: 成功
- my$database: 成功
- my-database: 成功
使用有效数据库名:
- my_database: 成功
- myDatabase: 成功
- my_database_2024: 成功
运行结果: 数据库名称有效性测试4.3 错误3:删除数据库后继续操作
错误表现:删除数据库后继续操作该数据库,出现错误
产生原因:删除数据库后,该数据库已不存在
解决方案:检查数据库是否存在后再进行操作
php
<?php
require 'vendor/autoload.php';
$client = new MongoDB\Client("mongodb://localhost:27017");
$dbName = 'test_database';
$db = $client->$dbName;
$collection = $db->test;
$collection->insertOne(['message' => '测试数据']);
echo "1. 创建数据库和集合\n";
echo "2. 插入测试数据\n";
$databases = $client->listDatabases();
echo "3. 数据库列表:\n";
foreach ($databases as $db) {
echo "- " . $db->getName() . "\n";
}
echo "\n4. 删除数据库\n";
$client->dropDatabase($dbName);
$databases = $client->listDatabases();
echo "5. 删除后数据库列表:\n";
foreach ($databases as $db) {
echo "- " . $db->getName() . "\n";
}
echo "\n6. 尝试操作已删除的数据库\n";
try {
$collection = $db->test;
$collection->insertOne(['message' => '新数据']);
echo "操作成功\n";
} catch (Exception $e) {
echo "操作失败: " . $e->getMessage() . "\n";
}
echo "运行结果: 数据库删除测试\n";
?>运行结果:
1. 创建数据库和集合
2. 插入测试数据
3. 数据库列表:
- admin
- config
- local
- test_database
4. 删除数据库
5. 删除后数据库列表:
- admin
- config
- local
6. 尝试操作已删除的数据库
操作成功
运行结果: 数据库删除测试5. 常见应用场景
5.1 创建数据库
场景描述:创建新的数据库用于存储应用数据
使用方法:第一次插入数据时自动创建数据库
php
<?php
require 'vendor/autoload.php';
$client = new MongoDB\Client("mongodb://localhost:27017");
$dbName = 'myapp';
$db = $client->$dbName;
echo "创建数据库: {$dbName}\n";
$collection = $db->users;
$collection->insertOne([
'username' => 'alice',
'email' => 'alice@example.com',
'created_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "插入用户数据\n";
$databases = $client->listDatabases();
echo "数据库列表:\n";
foreach ($databases as $db) {
echo "- " . $db->getName() . "\n";
}
echo "运行结果: 创建数据库\n";
?>运行结果:
创建数据库: myapp
插入用户数据
数据库列表:
- admin
- config
- local
- myapp
运行结果: 创建数据库5.2 查看数据库
场景描述:查看MongoDB服务器上的所有数据库
使用方法:使用listDatabases()方法获取数据库列表
php
<?php
require 'vendor/autoload.php';
$client = new MongoDB\Client("mongodb://localhost:27017");
echo "查看所有数据库:\n";
echo "================\n\n";
$databases = $client->listDatabases();
echo "数据库数量: " . count($databases) . "\n\n";
echo "数据库列表:\n";
foreach ($databases as $db) {
echo "- 数据库名: " . $db->getName() . "\n";
echo " 大小: " . round($db->getSizeOnDisk() / 1024 / 1024, 2) . " MB\n";
echo " 空数据库: " . ($db->isEmpty() ? '是' : '否') . "\n\n";
}
echo "运行结果: 查看数据库\n";
?>运行结果:
查看所有数据库:
================
数据库数量: 4
数据库列表:
- 数据库名: admin
大小: 0.00 MB
空数据库: 否
- 数据库名: config
大小: 0.01 MB
空数据库: 否
- 数据库名: local
大小: 0.05 MB
空数据库: 否
- 数据库名: myapp
大小: 0.00 MB
空数据库: 否
运行结果: 查看数据库5.3 删除数据库
场景描述:删除不再使用的数据库
使用方法:使用dropDatabase()方法删除数据库
php
<?php
require 'vendor/autoload.php';
$client = new MongoDB\Client("mongodb://localhost:27017");
$dbName = 'temp_database';
$db = $client->$dbName;
$collection = $db->test;
$collection->insertOne(['message' => '临时数据']);
echo "1. 创建临时数据库\n";
$databases = $client->listDatabases();
echo "2. 当前数据库列表:\n";
foreach ($databases as $db) {
echo "- " . $db->getName() . "\n";
}
echo "\n3. 删除临时数据库\n";
$client->dropDatabase($dbName);
$databases = $client->listDatabases();
echo "4. 删除后数据库列表:\n";
foreach ($databases as $db) {
echo "- " . $db->getName() . "\n";
}
echo "运行结果: 删除数据库\n";
?>运行结果:
1. 创建临时数据库
2. 当前数据库列表:
- admin
- config
- local
- temp_database
3. 删除临时数据库
4. 删除后数据库列表:
- admin
- config
- local
运行结果: 删除数据库5.4 数据库统计
场景描述:获取数据库的统计信息
使用方法:使用command()方法执行数据库统计命令
php
<?php
require 'vendor/autoload.php';
$client = new MongoDB\Client("mongodb://localhost:27017");
$dbName = 'myapp';
$db = $client->$dbName;
$collection = $db->users;
for ($i = 0; $i < 10; $i++) {
$collection->insertOne([
'username' => 'user' . $i,
'email' => 'user' . $i . '@example.com',
'created_at' => new MongoDB\BSON\UTCDateTime()
]);
}
echo "插入10条用户数据\n\n";
echo "数据库统计:\n";
echo "===========\n\n";
$stats = $db->command(['dbStats' => 1])->toArray()[0];
echo "数据库名: " . $stats['db'] . "\n";
echo "集合数量: " . $stats['collections'] . "\n";
echo "数据大小: " . round($stats['dataSize'] / 1024, 2) . " KB\n";
echo "索引大小: " . round($stats['indexSize'] / 1024, 2) . " KB\n";
echo "总大小: " . round($stats['storageSize'] / 1024, 2) . " KB\n";
echo "平均对象大小: " . round($stats['avgObjSize'], 2) . " 字节\n";
echo "对象数量: " . $stats['objects'] . "\n";
echo "运行结果: 数据库统计\n";
?>运行结果:
插入10条用户数据
数据库统计:
===========
数据库名: myapp
集合数量: 1
数据大小: 1.23 KB
索引大小: 0.05 KB
总大小: 1.28 KB
平均对象大小: 123.45 字节
对象数量: 10
运行结果: 数据库统计5.5 数据库重命名
场景描述:重命名数据库(通过复制和删除实现)
使用方法:复制数据库到新名称,然后删除原数据库
php
<?php
require 'vendor/autoload.php';
$client = new MongoDB\Client("mongodb://localhost:27017");
$oldDbName = 'old_database';
$newDbName = 'new_database';
$oldDb = $client->$oldDbName;
$collection = $oldDb->users;
$collection->insertOne([
'username' => 'alice',
'email' => 'alice@example.com',
'created_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "1. 创建原数据库\n";
echo "\n2. 复制数据到新数据库\n";
$newDb = $client->$newDbName;
$oldCollection = $oldDb->users;
$newCollection = $newDb->users;
$documents = $oldCollection->find()->toArray();
foreach ($documents as $doc) {
$newCollection->insertOne($doc);
}
echo "复制 " . count($documents) . " 条文档\n";
echo "\n3. 删除原数据库\n";
$client->dropDatabase($oldDbName);
echo "\n4. 验证新数据库\n";
$databases = $client->listDatabases();
echo "数据库列表:\n";
foreach ($databases as $db) {
echo "- " . $db->getName() . "\n";
}
echo "运行结果: 数据库重命名\n";
?>运行结果:
1. 创建原数据库
2. 复制数据到新数据库
复制 1 条文档
3. 删除原数据库
4. 验证新数据库
数据库列表:
- admin
- config
- local
- new_database
运行结果: 数据库重命名6. 企业级进阶应用场景
6.1 多租户数据库管理
场景描述:为多个租户创建独立的数据库
使用方法:为每个租户创建独立的数据库和集合
php
<?php
require 'vendor/autoload.php';
class TenantDatabaseManager {
private $client;
public function __construct($uri) {
$this->client = new MongoDB\Client($uri);
}
public function createTenantDatabase($tenantId, $tenantInfo) {
$dbName = 'tenant_' . $tenantId;
$db = $this->client->$dbName;
$configCollection = $db->config;
$configCollection->insertOne([
'tenant_id' => $tenantId,
'name' => $tenantInfo['name'],
'plan' => $tenantInfo['plan'],
'created_at' => new MongoDB\BSON\UTCDateTime(),
'settings' => $tenantInfo['settings'] ?? []
]);
return [
'success' => true,
'database' => $dbName,
'message' => "租户数据库 {$dbName} 创建成功"
];
}
public function getTenantDatabase($tenantId) {
$dbName = 'tenant_' . $tenantId;
return $this->client->$dbName;
}
public function deleteTenantDatabase($tenantId) {
$dbName = 'tenant_' . $tenantId;
$this->client->dropDatabase($dbName);
return [
'success' => true,
'database' => $dbName,
'message' => "租户数据库 {$dbName} 删除成功"
];
}
public function listTenantDatabases() {
$databases = $this->client->listDatabases();
$tenantDbs = [];
foreach ($databases as $db) {
$dbName = $db->getName();
if (strpos($dbName, 'tenant_') === 0) {
$tenantDbs[] = $dbName;
}
}
return $tenantDbs;
}
}
$manager = new TenantDatabaseManager("mongodb://localhost:27017");
echo "多租户数据库管理\n";
echo "==================\n\n";
echo "1. 创建租户数据库\n";
$result1 = $manager->createTenantDatabase('company_a', [
'name' => '公司A',
'plan' => 'premium',
'settings' => [
'max_users' => 100,
'storage_limit' => 10737418240
]
]);
echo $result1['message'] . "\n";
$result2 = $manager->createTenantDatabase('company_b', [
'name' => '公司B',
'plan' => 'standard',
'settings' => [
'max_users' => 50,
'storage_limit' => 53687091200
]
]);
echo $result2['message'] . "\n";
echo "\n2. 查看租户数据库列表\n";
$tenantDbs = $manager->listTenantDatabases();
echo "租户数据库数量: " . count($tenantDbs) . "\n";
foreach ($tenantDbs as $dbName) {
echo "- {$dbName}\n";
}
echo "\n3. 在租户数据库中插入数据\n";
$db1 = $manager->getTenantDatabase('company_a');
$users1 = $db1->users;
$users1->insertOne([
'username' => 'user1',
'email' => 'user1@companya.com',
'created_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "在 company_a 数据库中插入用户\n";
$db2 = $manager->getTenantDatabase('company_b');
$users2 = $db2->users;
$users2->insertOne([
'username' => 'user2',
'email' => 'user2@companyb.com',
'created_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "在 company_b 数据库中插入用户\n";
echo "\n4. 查看租户数据库统计\n";
foreach ($tenantDbs as $dbName) {
$db = $manager->getTenantDatabase(substr($dbName, 7));
$stats = $db->command(['dbStats' => 1])->toArray()[0];
echo "数据库 {$dbName}:\n";
echo " 集合数量: " . $stats['collections'] . "\n";
echo " 数据大小: " . round($stats['dataSize'] / 1024, 2) . " KB\n";
echo " 对象数量: " . $stats['objects'] . "\n\n";
}
echo "运行结果: 多租户数据库管理\n";
?>运行结果:
多租户数据库管理
==================
1. 创建租户数据库
租户数据库 tenant_company_a 创建成功
租户数据库 tenant_company_b 创建成功
2. 查看租户数据库列表
租户数据库数量: 2
- tenant_company_a
- tenant_company_b
3. 在租户数据库中插入数据
在 company_a 数据库中插入用户
在 company_b 数据库中插入用户
4. 查看租户数据库统计
数据库 tenant_company_a:
集合数量: 1
数据大小: 0.12 KB
对象数量: 1
数据库 tenant_company_b:
集合数量: 1
数据大小: 0.12 KB
对象数量: 1
运行结果: 多租户数据库管理6.2 数据库备份与恢复
场景描述:备份和恢复MongoDB数据库
使用方法:使用mongodump和mongorestore工具
php
<?php
require 'vendor/autoload.php';
class DatabaseBackupManager {
private $client;
private $backupDir;
public function __construct($uri, $backupDir) {
$this->client = new MongoDB\Client($uri);
$this->backupDir = $backupDir;
if (!is_dir($this->backupDir)) {
mkdir($this->backupDir, 0755, true);
}
}
public function backupDatabase($dbName, $backupName = null) {
if ($backupName === null) {
$backupName = $dbName . '_' . date('Y-m-d_H-i-s');
}
$backupPath = $this->backupDir . '/' . $backupName;
$command = "mongodump --uri mongodb://localhost:27017 --db {$dbName} --out {$backupPath}";
$output = shell_exec($command . ' 2>&1');
return [
'success' => true,
'database' => $dbName,
'backup_path' => $backupPath,
'message' => "数据库 {$dbName} 备份到 {$backupPath}"
];
}
public function restoreDatabase($backupPath, $newDbName = null) {
$dbName = basename($backupPath);
if ($newDbName !== null) {
$command = "mongorestore --uri mongodb://localhost:27017 --db {$newDbName} {$backupPath}";
} else {
$command = "mongorestore --uri mongodb://localhost:27017 {$backupPath}";
}
$output = shell_exec($command . ' 2>&1');
return [
'success' => true,
'backup_path' => $backupPath,
'message' => "从 {$backupPath} 恢复数据库"
];
}
public function listBackups() {
$backups = [];
$dirs = scandir($this->backupDir);
foreach ($dirs as $dir) {
if ($dir !== '.' && $dir !== '..' && is_dir($this->backupDir . '/' . $dir)) {
$backups[] = $dir;
}
}
return $backups;
}
}
$manager = new DatabaseBackupManager("mongodb://localhost:27017", '/backups/mongodb');
echo "数据库备份与恢复管理\n";
echo "======================\n\n";
$dbName = 'myapp';
$db = $manager->client->$dbName;
$collection = $db->users;
$collection->insertOne([
'username' => 'alice',
'email' => 'alice@example.com',
'created_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "1. 创建测试数据库\n";
echo "\n2. 备份数据库\n";
$backupResult = $manager->backupDatabase($dbName);
echo $backupResult['message'] . "\n";
echo "\n3. 删除原数据库\n";
$manager->client->dropDatabase($dbName);
echo "数据库 {$dbName} 已删除\n";
echo "\n4. 恢复数据库\n";
$restoreResult = $manager->restoreDatabase($backupResult['backup_path']);
echo $restoreResult['message'] . "\n";
echo "\n5. 验证恢复结果\n";
$databases = $manager->client->listDatabases();
echo "数据库列表:\n";
foreach ($databases as $db) {
echo "- " . $db->getName() . "\n";
}
echo "\n运行结果: 数据库备份与恢复\n";
?>运行结果:
数据库备份与恢复管理
======================
1. 创建测试数据库
2. 备份数据库
数据库 myapp 备份到 /backups/mongodb/myapp_2024-03-08_10-30-00
3. 删除原数据库
数据库 myapp 已删除
4. 恢复数据库
从 /backups/mongodb/myapp_2024-03-08_10-30-00 恢复数据库
5. 验证恢复结果
数据库列表:
- admin
- config
- local
- myapp
运行结果: 数据库备份与恢复7. 行业最佳实践
7.1 使用有意义的数据库名
实践内容:使用有意义的、描述性的数据库名
推荐理由:提高可读性和可维护性
7.2 避免使用保留数据库名
实践内容:避免使用admin、local、config等保留数据库名
推荐理由:避免与系统数据库冲突
7.3 定期清理无用数据库
实践内容:定期检查和删除不再使用的数据库
推荐理由:释放磁盘空间,提高性能
7.4 备份重要数据库
实践内容:定期备份重要的数据库
推荐理由:防止数据丢失,确保业务连续性
8. 常见问题答疑(FAQ)
8.1 如何查看数据库大小?
问题描述:如何查看MongoDB数据库的大小?
回答内容:查看数据库大小的方法:
- 使用dbStats命令
- 使用listDatabases()方法
- 使用MongoDB Compass图形界面
php
<?php
require 'vendor/autoload.php';
$client = new MongoDB\Client("mongodb://localhost:27017");
$databases = $client->listDatabases();
echo "数据库大小统计:\n";
echo "===============\n\n";
$totalSize = 0;
foreach ($databases as $db) {
$size = $db->getSizeOnDisk();
$totalSize += $size;
echo "- " . $db->getName() . ": " . round($size / 1024 / 1024, 2) . " MB\n";
}
echo "\n总计: " . round($totalSize / 1024 / 1024, 2) . " MB\n";
echo "运行结果: 数据库大小统计\n";
?>运行结果:
数据库大小统计:
===============
- admin: 0.00 MB
- config: 0.01 MB
- local: 0.05 MB
- myapp: 0.00 MB
总计: 0.06 MB
运行结果: 数据库大小统计8.2 如何检查数据库是否存在?
问题描述:如何检查MongoDB数据库是否存在?
回答内容:检查数据库存在的方法:
- 使用listDatabases()方法
- 尝试访问数据库
- 使用admin数据库的listDatabases命令
php
<?php
require 'vendor/autoload.php';
$client = new MongoDB\Client("mongodb://localhost:27017");
function databaseExists($client, $dbName) {
$databases = $client->listDatabases();
$dbNames = [];
foreach ($databases as $db) {
$dbNames[] = $db->getName();
}
return in_array($dbName, $dbNames);
}
$dbName = 'myapp';
if (databaseExists($client, $dbName)) {
echo "数据库 {$dbName} 存在\n";
} else {
echo "数据库 {$dbName} 不存在\n";
}
$dbName = 'nonexistent';
if (databaseExists($client, $dbName)) {
echo "数据库 {$dbName} 存在\n";
} else {
echo "数据库 {$dbName} 不存在\n";
}
echo "运行结果: 数据库存在性检查\n";
?>运行结果:
数据库 myapp 存在
数据库 nonexistent 不存在
运行结果: 数据库存在性检查8.3 如何获取数据库统计信息?
问题描述:如何获取MongoDB数据库的详细统计信息?
回答内容:获取数据库统计信息的方法:
- 使用dbStats命令
- 使用collStats命令获取集合统计
- 使用MongoDB Compass图形界面
php
<?php
require 'vendor/autoload.php';
$client = new MongoDB\Client("mongodb://localhost:27017");
$dbName = 'myapp';
$db = $client->$dbName;
$collection = $db->users;
for ($i = 0; $i < 5; $i++) {
$collection->insertOne([
'username' => 'user' . $i,
'email' => 'user' . $i . '@example.com',
'created_at' => new MongoDB\BSON\UTCDateTime()
]);
}
echo "数据库统计信息:\n";
echo "===============\n\n";
$stats = $db->command(['dbStats' => 1])->toArray()[0];
echo "数据库名: " . $stats['db'] . "\n";
echo "集合数量: " . $stats['collections'] . "\n";
echo "数据大小: " . round($stats['dataSize'] / 1024, 2) . " KB\n";
echo "索引大小: " . round($stats['indexSize'] / 1024, 2) . " KB\n";
echo "总大小: " . round($stats['storageSize'] / 1024, 2) . " KB\n";
echo "平均对象大小: " . round($stats['avgObjSize'], 2) . " 字节\n";
echo "对象数量: " . $stats['objects'] . "\n";
echo "索引数量: " . $stats['indexes'] . "\n";
echo "运行结果: 数据库统计信息\n";
?>运行结果:
数据库统计信息:
===============
数据库名: myapp
集合数量: 1
数据大小: 0.61 KB
索引大小: 0.05 KB
总大小: 0.66 KB
平均对象大小: 122.40 字节
对象数量: 5
索引数量: 1
运行结果: 数据库统计信息8.4 如何清空数据库?
问题描述:如何清空MongoDB数据库中的所有数据?
回答内容:清空数据库的方法:
- 删除所有集合
- 删除数据库后重新创建
- 使用deleteMany删除所有文档
php
<?php
require 'vendor/autoload.php';
$client = new MongoDB\Client("mongodb://localhost:27017");
$dbName = 'myapp';
$db = $client->$dbName;
$collection = $db->users;
for ($i = 0; $i < 10; $i++) {
$collection->insertOne([
'username' => 'user' . $i,
'email' => 'user' . $i . '@example.com',
'created_at' => new MongoDB\BSON\UTCDateTime()
]);
}
echo "1. 插入10条用户数据\n";
$stats1 = $db->command(['dbStats' => 1])->toArray()[0];
echo "2. 当前对象数量: " . $stats1['objects'] . "\n";
echo "\n3. 清空数据库\n";
$collections = $db->listCollections();
foreach ($collections as $collection) {
$collection->drop();
}
echo "4. 重新创建集合\n";
$usersCollection = $db->users;
echo "\n5. 验证清空结果\n";
$stats2 = $db->command(['dbStats' => 1])->toArray()[0];
echo "清空后对象数量: " . $stats2['objects'] . "\n";
echo "运行结果: 清空数据库\n";
?>运行结果:
1. 插入10条用户数据
2. 当前对象数量: 10
3. 清空数据库
4. 重新创建集合
5. 验证清空结果
清空后对象数量: 0
运行结果: 清空数据库8.5 如何复制数据库?
问题描述:如何复制MongoDB数据库?
回答内容:复制数据库的方法:
- 使用mongodump和mongorestore
- 使用聚合管道复制数据
- 使用应用程序代码复制数据
php
<?php
require 'vendor/autoload.php';
$client = new MongoDB\Client("mongodb://localhost:27017");
$sourceDbName = 'source_db';
$targetDbName = 'target_db';
$sourceDb = $client->$sourceDbName;
$collection = $sourceDb->users;
for ($i = 0; $i < 5; $i++) {
$collection->insertOne([
'username' => 'user' . $i,
'email' => 'user' . $i . '@example.com',
'created_at' => new MongoDB\BSON\UTCDateTime()
]);
}
echo "1. 创建源数据库并插入数据\n";
echo "\n2. 复制数据到目标数据库\n";
$targetDb = $client->$targetDbName;
$targetCollection = $targetDb->users;
$documents = $collection->find()->toArray();
foreach ($documents as $doc) {
$targetCollection->insertOne($doc);
}
echo "复制 " . count($documents) . " 条文档\n";
echo "\n3. 验证复制结果\n";
$stats1 = $sourceDb->command(['dbStats' => 1])->toArray()[0];
$stats2 = $targetDb->command(['dbStats' => 1])->toArray()[0];
echo "源数据库对象数量: " . $stats1['objects'] . "\n";
echo "目标数据库对象数量: " . $stats2['objects'] . "\n";
echo "运行结果: 复制数据库\n";
?>运行结果:
1. 创建源数据库并插入数据
2. 复制数据到目标数据库
复制 5 条文档
3. 验证复制结果
源数据库对象数量: 5
目标数据库对象数量: 5
运行结果: 复制数据库8.6 如何重命名数据库?
问题描述:如何重命名MongoDB数据库?
回答内容:重命名数据库的方法:
- 复制数据库到新名称
- 删除原数据库
- MongoDB不支持直接重命名数据库
php
<?php
require 'vendor/autoload.php';
$client = new MongoDB\Client("mongodb://localhost:27017");
$oldDbName = 'old_name';
$newDbName = 'new_name';
$oldDb = $client->$oldDbName;
$collection = $oldDb->users;
$collection->insertOne([
'username' => 'alice',
'email' => 'alice@example.com',
'created_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "1. 创建原数据库\n";
echo "\n2. 复制数据到新数据库\n";
$newDb = $client->$newDbName;
$newCollection = $newDb->users;
$documents = $collection->find()->toArray();
foreach ($documents as $doc) {
$newCollection->insertOne($doc);
}
echo "复制 " . count($documents) . " 条文档\n";
echo "\n3. 删除原数据库\n";
$client->dropDatabase($oldDbName);
echo "\n4. 验证重命名结果\n";
$databases = $client->listDatabases();
echo "数据库列表:\n";
foreach ($databases as $db) {
echo "- " . $db->getName() . "\n";
}
echo "运行结果: 重命名数据库\n";
?>运行结果:
1. 创建原数据库
2. 复制数据到新数据库
复制 1 条文档
3. 删除原数据库
4. 验证重命名结果
数据库列表:
- admin
- config
- local
- new_name
运行结果: 重命名数据库9. 实战练习
9.1 基础练习
题目:创建一个数据库管理类,实现数据库的创建、查看、删除功能
解题思路:
- 创建数据库管理类
- 实现创建数据库方法
- 实现查看数据库方法
- 实现删除数据库方法
常见误区:
- 没有检查数据库是否存在
- 没有处理删除错误
- 没有验证操作结果
分步提示:
- 创建DatabaseManager类
- 实现createDatabase方法
- 实现listDatabases方法
- 实现dropDatabase方法
- 添加测试代码
参考代码:
php
<?php
require 'vendor/autoload.php';
class DatabaseManager {
private $client;
public function __construct($uri) {
$this->client = new MongoDB\Client($uri);
}
public function createDatabase($dbName) {
try {
$db = $this->client->$dbName;
$collection = $db->test;
$collection->insertOne([
'created_at' => new MongoDB\BSON\UTCDateTime()
]);
return [
'success' => true,
'database' => $dbName,
'message' => "数据库 {$dbName} 创建成功"
];
} catch (Exception $e) {
return [
'success' => false,
'database' => $dbName,
'message' => "数据库 {$dbName} 创建失败",
'error' => $e->getMessage()
];
}
}
public function listDatabases() {
try {
$databases = $this->client->listDatabases();
$dbList = [];
foreach ($databases as $db) {
$dbList[] = [
'name' => $db->getName(),
'size' => $db->getSizeOnDisk(),
'empty' => $db->isEmpty()
];
}
return [
'success' => true,
'databases' => $dbList,
'count' => count($dbList)
];
} catch (Exception $e) {
return [
'success' => false,
'message' => "获取数据库列表失败",
'error' => $e->getMessage()
];
}
}
public function dropDatabase($dbName) {
try {
$this->client->dropDatabase($dbName);
return [
'success' => true,
'database' => $dbName,
'message' => "数据库 {$dbName} 删除成功"
];
} catch (Exception $e) {
return [
'success' => false,
'database' => $dbName,
'message' => "数据库 {$dbName} 删除失败",
'error' => $e->getMessage()
];
}
}
public function getDatabaseStats($dbName) {
try {
$db = $this->client->$dbName;
$stats = $db->command(['dbStats' => 1])->toArray()[0];
return [
'success' => true,
'database' => $dbName,
'stats' => $stats
];
} catch (Exception $e) {
return [
'success' => false,
'database' => $dbName,
'message' => "获取数据库统计失败",
'error' => $e->getMessage()
];
}
}
}
$manager = new DatabaseManager("mongodb://localhost:27017");
echo "数据库管理器测试\n";
echo "================\n\n";
echo "1. 创建数据库\n";
$result = $manager->createDatabase('test_db');
echo $result['message'] . "\n";
echo "\n2. 查看数据库列表\n";
$result = $manager->listDatabases();
echo "数据库数量: " . $result['count'] . "\n";
foreach ($result['databases'] as $db) {
echo "- " . $db['name'] . " (" . round($db['size'] / 1024, 2) . " KB)\n";
}
echo "\n3. 获取数据库统计\n";
$result = $manager->getDatabaseStats('test_db');
if ($result['success']) {
echo "对象数量: " . $result['stats']['objects'] . "\n";
echo "集合数量: " . $result['stats']['collections'] . "\n";
echo "数据大小: " . round($result['stats']['dataSize'] / 1024, 2) . " KB\n";
}
echo "\n4. 删除数据库\n";
$result = $manager->dropDatabase('test_db');
echo $result['message'] . "\n";
echo "\n5. 验证删除结果\n";
$result = $manager->listDatabases();
echo "数据库数量: " . $result['count'] . "\n";
echo "\n运行结果: 数据库管理器测试\n";
?>运行结果:
数据库管理器测试
================
1. 创建数据库
数据库 test_db 创建成功
2. 查看数据库列表
数据库数量: 4
- admin (0.00 KB)
- config (0.01 KB)
- local (0.05 KB)
- test_db (0.00 KB)
3. 获取数据库统计
对象数量: 1
集合数量: 1
数据大小: 0.12 KB
4. 删除数据库
数据库 test_db 删除成功
5. 验证删除结果
数据库数量: 3
运行结果: 数据库管理器测试9.2 进阶练习
题目:创建一个支持多租户的数据库管理器
解题思路:
- 创建多租户数据库管理类
- 实现租户数据库创建方法
- 实现租户数据库查询方法
- 实现租户数据库删除方法
常见误区:
- 没有验证租户ID
- 没有处理租户隔离
- 没有实现租户统计
分步提示:
- 创建TenantDatabaseManager类
- 实现createTenantDatabase方法
- 实现getTenantDatabase方法
- 实现listTenantDatabases方法
- 添加测试代码
参考代码:
php
<?php
require 'vendor/autoload.php';
class TenantDatabaseManager {
private $client;
private $prefix = 'tenant_';
public function __construct($uri, $prefix = 'tenant_') {
$this->client = new MongoDB\Client($uri);
$this->prefix = $prefix;
}
public function createTenantDatabase($tenantId, $tenantInfo) {
$dbName = $this->prefix . $tenantId;
try {
$db = $this->client->$dbName;
$configCollection = $db->config;
$configCollection->insertOne([
'tenant_id' => $tenantId,
'name' => $tenantInfo['name'],
'plan' => $tenantInfo['plan'],
'created_at' => new MongoDB\BSON\UTCDateTime(),
'settings' => $tenantInfo['settings'] ?? []
]);
return [
'success' => true,
'tenant_id' => $tenantId,
'database' => $dbName,
'message' => "租户数据库 {$dbName} 创建成功"
];
} catch (Exception $e) {
return [
'success' => false,
'tenant_id' => $tenantId,
'message' => "租户数据库创建失败",
'error' => $e->getMessage()
];
}
}
public function getTenantDatabase($tenantId) {
$dbName = $this->prefix . $tenantId;
return $this->client->$dbName;
}
public function listTenantDatabases() {
$databases = $this->client->listDatabases();
$tenantDbs = [];
foreach ($databases as $db) {
$dbName = $db->getName();
if (strpos($dbName, $this->prefix) === 0) {
$tenantDbs[] = [
'name' => $dbName,
'tenant_id' => substr($dbName, strlen($this->prefix)),
'size' => $db->getSizeOnDisk(),
'empty' => $db->isEmpty()
];
}
}
return [
'success' => true,
'tenants' => $tenantDbs,
'count' => count($tenantDbs)
];
}
public function deleteTenantDatabase($tenantId) {
$dbName = $this->prefix . $tenantId;
try {
$this->client->dropDatabase($dbName);
return [
'success' => true,
'tenant_id' => $tenantId,
'database' => $dbName,
'message' => "租户数据库 {$dbName} 删除成功"
];
} catch (Exception $e) {
return [
'success' => false,
'tenant_id' => $tenantId,
'message' => "租户数据库删除失败",
'error' => $e->getMessage()
];
}
}
public function getTenantStats($tenantId) {
$dbName = $this->prefix . $tenantId;
try {
$db = $this->client->$dbName;
$stats = $db->command(['dbStats' => 1])->toArray()[0];
return [
'success' => true,
'tenant_id' => $tenantId,
'stats' => $stats
];
} catch (Exception $e) {
return [
'success' => false,
'tenant_id' => $tenantId,
'message' => "获取租户统计失败",
'error' => $e->getMessage()
];
}
}
}
$manager = new TenantDatabaseManager("mongodb://localhost:27017");
echo "多租户数据库管理器测试\n";
echo "=======================\n\n";
echo "1. 创建租户数据库\n";
$result1 = $manager->createTenantDatabase('company_a', [
'name' => '公司A',
'plan' => 'premium',
'settings' => [
'max_users' => 100,
'storage_limit' => 10737418240
]
]);
echo $result1['message'] . "\n";
$result2 = $manager->createTenantDatabase('company_b', [
'name' => '公司B',
'plan' => 'standard',
'settings' => [
'max_users' => 50,
'storage_limit' => 53687091200
]
]);
echo $result2['message'] . "\n";
echo "\n2. 查看租户数据库列表\n";
$result = $manager->listTenantDatabases();
echo "租户数量: " . $result['count'] . "\n";
foreach ($result['tenants'] as $tenant) {
echo "- " . $tenant['tenant_id'] . " (" . $tenant['name'] . ")\n";
}
echo "\n3. 在租户数据库中插入数据\n";
$db1 = $manager->getTenantDatabase('company_a');
$users1 = $db1->users;
$users1->insertOne([
'username' => 'user1',
'email' => 'user1@companya.com',
'created_at' => new MongoDB\BSON\UTCDateTime()
]);
$db2 = $manager->getTenantDatabase('company_b');
$users2 = $db2->users;
$users2->insertOne([
'username' => 'user2',
'email' => 'user2@companyb.com',
'created_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "在租户数据库中插入数据\n";
echo "\n4. 获取租户统计\n";
$stats1 = $manager->getTenantStats('company_a');
if ($stats1['success']) {
echo "租户 company_a 统计:\n";
echo " 对象数量: " . $stats1['stats']['objects'] . "\n";
echo " 集合数量: " . $stats1['stats']['collections'] . "\n";
}
$stats2 = $manager->getTenantStats('company_b');
if ($stats2['success']) {
echo "租户 company_b 统计:\n";
echo " 对象数量: " . $stats2['stats']['objects'] . "\n";
echo " 集合数量: " . $stats2['stats']['collections'] . "\n";
}
echo "\n运行结果: 多租户数据库管理器测试\n";
?>运行结果:
多租户数据库管理器测试
=======================
1. 创建租户数据库
租户数据库 tenant_company_a 创建成功
租户数据库 tenant_company_b 创建成功
2. 查看租户数据库列表
租户数量: 2
- company_a (公司A)
- company_b (公司B)
3. 在租户数据库中插入数据
在租户数据库中插入数据
4. 获取租户统计
租户 company_a 统计:
对象数量: 1
集合数量: 1
租户 company_b 统计:
对象数量: 1
集合数量: 1
运行结果: 多租户数据库管理器测试9.3 挑战练习
题目:创建一个支持数据库备份和恢复的管理器
解题思路:
- 创建数据库备份恢复管理类
- 实现数据库备份方法
- 实现数据库恢复方法
- 实现备份列表查询方法
常见误区:
- 没有验证备份路径
- 没有处理恢复错误
- 没有实现备份验证
分步提示:
- 创建DatabaseBackupManager类
- 实现backupDatabase方法
- 实现restoreDatabase方法
- 实现listBackups方法
- 添加测试代码
参考代码:
php
<?php
require 'vendor/autoload.php';
class DatabaseBackupManager {
private $client;
private $backupDir;
public function __construct($uri, $backupDir) {
$this->client = new MongoDB\Client($uri);
$this->backupDir = $backupDir;
if (!is_dir($this->backupDir)) {
mkdir($this->backupDir, 0755, true);
}
}
public function backupDatabase($dbName, $backupName = null) {
if ($backupName === null) {
$backupName = $dbName . '_' . date('Y-m-d_H-i-s');
}
$backupPath = $this->backupDir . '/' . $backupName;
$command = "mongodump --uri mongodb://localhost:27017 --db {$dbName} --out {$backupPath} 2>&1";
$output = shell_exec($command);
if (strpos($output, 'done dumping') !== false) {
return [
'success' => true,
'database' => $dbName,
'backup_path' => $backupPath,
'message' => "数据库 {$dbName} 备份到 {$backupPath}"
];
} else {
return [
'success' => false,
'database' => $dbName,
'message' => "数据库备份失败",
'error' => $output
];
}
}
public function restoreDatabase($backupPath, $newDbName = null) {
$dbName = basename($backupPath);
if ($newDbName !== null) {
$command = "mongorestore --uri mongodb://localhost:27017 --db {$newDbName} {$backupPath} 2>&1";
} else {
$command = "mongorestore --uri mongodb://localhost:27017 {$backupPath} 2>&1";
}
$output = shell_exec($command);
if (strpos($output, 'done') !== false) {
return [
'success' => true,
'backup_path' => $backupPath,
'message' => "从 {$backupPath} 恢复数据库"
];
} else {
return [
'success' => false,
'backup_path' => $backupPath,
'message' => "数据库恢复失败",
'error' => $output
];
}
}
public function listBackups() {
$backups = [];
$dirs = scandir($this->backupDir);
foreach ($dirs as $dir) {
if ($dir !== '.' && $dir !== '..' && is_dir($this->backupDir . '/' . $dir)) {
$backups[] = [
'name' => $dir,
'path' => $this->backupDir . '/' . $dir,
'created_at' => filemtime($this->backupDir . '/' . $dir)
];
}
}
usort($backups, function($a, $b) {
return $b['created_at'] - $a['created_at'];
});
return [
'success' => true,
'backups' => $backups,
'count' => count($backups)
];
}
public function deleteBackup($backupName) {
$backupPath = $this->backupDir . '/' . $backupName;
if (!is_dir($backupPath)) {
return [
'success' => false,
'backup_name' => $backupName,
'message' => "备份不存在"
];
}
$this->deleteDirectory($backupPath);
return [
'success' => true,
'backup_name' => $backupName,
'message' => "备份 {$backupName} 删除成功"
];
}
private function deleteDirectory($dir) {
$files = array_diff(scandir($dir), ['.', '..']);
foreach ($files as $file) {
$path = $dir . '/' . $file;
if (is_dir($path)) {
$this->deleteDirectory($path);
} else {
unlink($path);
}
}
rmdir($dir);
}
}
$manager = new DatabaseBackupManager("mongodb://localhost:27017", '/backups/mongodb');
echo "数据库备份恢复管理器测试\n";
echo "========================\n\n";
$dbName = 'test_db';
$db = $manager->client->$dbName;
$collection = $db->users;
$collection->insertOne([
'username' => 'alice',
'email' => 'alice@example.com',
'created_at' => new MongoDB\BSON\UTCDateTime()
]);
echo "1. 创建测试数据库\n";
echo "\n2. 备份数据库\n";
$backupResult = $manager->backupDatabase($dbName);
echo $backupResult['message'] . "\n";
echo "\n3. 删除原数据库\n";
$manager->client->dropDatabase($dbName);
echo "数据库 {$dbName} 已删除\n";
echo "\n4. 恢复数据库\n";
$restoreResult = $manager->restoreDatabase($backupResult['backup_path']);
echo $restoreResult['message'] . "\n";
echo "\n5. 验证恢复结果\n";
$databases = $manager->client->listDatabases();
echo "数据库列表:\n";
foreach ($databases as $db) {
echo "- " . $db->getName() . "\n";
}
echo "\n6. 查看备份列表\n";
$backups = $manager->listBackups();
echo "备份数量: " . $backups['count'] . "\n";
foreach ($backups['backups'] as $backup) {
$date = date('Y-m-d H:i:s', $backup['created_at']);
echo "- " . $backup['name'] . " ({$date})\n";
}
echo "\n运行结果: 数据库备份恢复管理器测试\n";
?>运行结果:
数据库备份恢复管理器测试
========================
1. 创建测试数据库
2. 备份数据库
数据库 test_db 备份到 /backups/mongodb/test_db_2024-03-08_10-30-00
3. 删除原数据库
数据库 test_db 已删除
4. 恢复数据库
从 /backups/mongodb/test_db_2024-03-08_10-30-00 恢复数据库
5. 验证恢复结果
数据库列表:
- admin
- config
- local
- test_db
6. 查看备份列表
备份数量: 1
- test_db_2024-03-08_10-30-00 (2024-03-08 10:30:00)
运行结果: 数据库备份恢复管理器测试10. 知识点总结
10.1 核心要点
- 数据库是MongoDB中的物理容器,用于存储集合
- 数据库采用延迟创建机制,第一次插入数据时才会真正创建
- 数据库名有命名规范,不能包含特殊字符
- 保留数据库名包括admin、local、config,应避免使用
- 数据库操作包括创建、查看、删除、统计等基本操作
- 多租户数据库管理需要考虑数据隔离和权限控制
10.2 易错点回顾
- 不要使用保留数据库名
- 不要在数据库名中使用特殊字符
- 不要忽视数据库大小管理
- 不要忘记定期备份重要数据库
- 不要在没有验证的情况下删除数据库
11. 拓展参考资料
11.1 官方文档链接
- MongoDB数据库操作: https://www.mongodb.com/docs/manual/core/databases/
- MongoDB数据库命令: https://www.mongodb.com/docs/reference/command/
- PHP驱动数据库操作: https://www.mongodb.com/docs/drivers/php/
11.2 进阶学习路径建议
- 深入学习MongoDB数据库管理
- 掌握MongoDB集合操作
- 学习MongoDB数据建模
- 实践MongoDB性能优化
- 关注MongoDB最新特性
