Skip to content

4.4 删除文档 (Delete)

概述

删除文档是MongoDB中移除数据的核心操作。MongoDB提供了灵活的删除功能,支持单文档删除、批量删除、条件删除等多种删除方式。本章节将详细介绍MongoDB文档删除的各种方法、删除策略和性能优化技巧。

MongoDB的删除操作具有原子性、灵活性和高性能的特点。掌握删除操作对于维护数据完整性和实现数据生命周期管理至关重要。

基本概念

删除方法

MongoDB提供以下删除方法:

  1. deleteOne():删除单个文档
  2. deleteMany():删除多个文档
  3. findOneAndDelete():查找并删除单个文档
  4. bulkWrite():批量执行删除操作

删除策略

MongoDB支持以下删除策略:

  • 精确删除:根据精确条件删除文档
  • 范围删除:根据范围条件删除文档
  • 批量删除:一次性删除多个文档
  • 条件删除:使用复杂条件删除文档

删除选项

删除支持以下选项:

  • writeConcern:写入关注级别
  • collation:指定排序规则
  • hint:使用指定索引
  • timeout:操作超时设置

原理深度解析

单文档删除原理

使用deleteOne()方法删除单个文档:

php
<?php
// 单文档删除详解
class SingleDocumentDelete {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    public function deleteById($collectionName, $id) {
        $collection = $this->database->selectCollection($collectionName);
        
        try {
            $result = $collection->deleteOne(['_id' => new MongoDB\BSON\ObjectId($id)]);
            
            return [
                'success' => true,
                'deleted_count' => $result->getDeletedCount(),
                'acknowledged' => $result->isAcknowledged()
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Delete failed',
                'message' => $e->getMessage()
            ];
        }
    }
    
    public function deleteByField($collectionName, $field, $value) {
        $collection = $this->database->selectCollection($collectionName);
        
        try {
            $result = $collection->deleteOne([$field => $value]);
            
            return [
                'success' => true,
                'field' => $field,
                'value' => $value,
                'deleted_count' => $result->getDeletedCount()
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Delete failed',
                'message' => $e->getMessage()
            ];
        }
    }
    
    public function deleteByMultipleFields($collectionName, $conditions) {
        $collection = $this->database->selectCollection($collectionName);
        
        try {
            $result = $collection->deleteOne($conditions);
            
            return [
                'success' => true,
                'conditions' => $conditions,
                'deleted_count' => $result->getDeletedCount()
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Delete failed',
                'message' => $e->getMessage()
            ];
        }
    }
    
    public function deleteWithVerification($collectionName, $filter) {
        $collection = $this->database->selectCollection($collectionName);
        
        try {
            // 先查找要删除的文档
            $document = $collection->findOne($filter);
            
            if (!$document) {
                return [
                    'success' => false,
                    'message' => 'Document not found',
                    'deleted_count' => 0
                ];
            }
            
            // 删除文档
            $result = $collection->deleteOne($filter);
            
            return [
                'success' => true,
                'deleted_document' => $document,
                'deleted_count' => $result->getDeletedCount(),
                'verified' => true
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Delete failed',
                'message' => $e->getMessage()
            ];
        }
    }
}

// 使用示例
$singleDelete = new SingleDocumentDelete('testdb');

// 按ID删除
$idResult = $singleDelete->deleteById('users', '507f1f77bcf86cd799439011');
print_r($idResult);

// 按字段删除
$fieldResult = $singleDelete->deleteByField('users', 'email', 'john@example.com');
print_r($fieldResult);

// 按多个字段删除
$conditions = [
    'name' => 'John Doe',
    'status' => 'inactive'
];

$multipleResult = $singleDelete->deleteByMultipleFields('users', $conditions);
print_r($multipleResult);

// 带验证的删除
$verificationResult = $singleDelete->deleteWithVerification('users', ['email' => 'jane@example.com']);
print_r($verificationResult);
?>

批量删除原理

使用deleteMany()方法删除多个文档:

php
<?php
// 批量删除详解
class BatchDocumentDelete {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    public function deleteManyDocuments($collectionName, $filter) {
        $collection = $this->database->selectCollection($collectionName);
        
        try {
            $result = $collection->deleteMany($filter);
            
            return [
                'success' => true,
                'deleted_count' => $result->getDeletedCount(),
                'acknowledged' => $result->isAcknowledged()
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Batch delete failed',
                'message' => $e->getMessage()
            ];
        }
    }
    
    public function deleteWithProgress($collectionName, $filter, $batchSize = 1000, $callback = null) {
        $collection = $this->database->selectCollection($collectionName);
        
        $results = [
            'total_deleted' => 0,
            'batch_count' => 0,
            'batch_results' => []
        ];
        
        try {
            // 获取匹配的文档总数
            $totalMatched = $collection->countDocuments($filter);
            
            if ($totalMatched === 0) {
                return [
                    'success' => true,
                    'message' => 'No documents matched the filter',
                    'total_deleted' => 0
                ];
            }
            
            // 分批删除
            $deletedCount = 0;
            while ($deletedCount < $totalMatched) {
                $result = $collection->deleteMany($filter);
                $batchDeleted = $result->getDeletedCount();
                
                $batchResult = [
                    'batch_number' => $results['batch_count'] + 1,
                    'deleted_count' => $batchDeleted,
                    'status' => 'success'
                ];
                
                $results['total_deleted'] += $batchDeleted;
                $results['batch_count']++;
                $results['batch_results'][] = $batchResult;
                
                // 调用回调函数
                if ($callback && is_callable($callback)) {
                    $callback($batchResult, $results['batch_count']);
                }
                
                $deletedCount += $batchDeleted;
                
                // 如果没有删除更多文档,退出循环
                if ($batchDeleted === 0) {
                    break;
                }
            }
            
            return [
                'success' => true,
                'total_matched' => $totalMatched,
                'total_deleted' => $results['total_deleted'],
                'batch_count' => $results['batch_count'],
                'batch_results' => $results['batch_results']
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Batch delete failed',
                'message' => $e->getMessage(),
                'partial_results' => $results
            ];
        }
    }
    
    public function deleteByDateRange($collectionName, $dateField, $startDate, $endDate) {
        $collection = $this->database->selectCollection($collectionName);
        
        try {
            $filter = [
                $dateField => [
                    '$gte' => $startDate,
                    '$lte' => $endDate
                ]
            ];
            
            $result = $collection->deleteMany($filter);
            
            return [
                'success' => true,
                'date_field' => $dateField,
                'date_range' => [
                    'start' => $startDate->toDateTime()->format('Y-m-d H:i:s'),
                    'end' => $endDate->toDateTime()->format('Y-m-d H:i:s')
                ],
                'deleted_count' => $result->getDeletedCount()
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Date range delete failed',
                'message' => $e->getMessage()
            ];
        }
    }
    
    public function deleteOldDocuments($collectionName, $dateField, $cutoffDate) {
        $collection = $this->database->selectCollection($collectionName);
        
        try {
            $filter = [
                $dateField => ['$lt' => $cutoffDate]
            ];
            
            $result = $collection->deleteMany($filter);
            
            return [
                'success' => true,
                'date_field' => $dateField,
                'cutoff_date' => $cutoffDate->toDateTime()->format('Y-m-d H:i:s'),
                'deleted_count' => $result->getDeletedCount()
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Old documents delete failed',
                'message' => $e->getMessage()
            ];
        }
    }
}

// 使用示例
$batchDelete = new BatchDocumentDelete('testdb');

// 批量删除
$filter = ['status' => 'inactive'];
$result = $batchDelete->deleteManyDocuments('users', $filter);
print_r($result);

// 带进度的批量删除
$progressCallback = function($batchResult, $batchNumber) {
    echo "Batch {$batchNumber}: Deleted {$batchResult['deleted_count']} documents\n";
};

$progressResult = $batchDelete->deleteWithProgress('users', $filter, 1000, $progressCallback);
print_r($progressResult);

// 按日期范围删除
$startDate = new MongoDB\BSON\UTCDateTime(strtotime('2024-01-01') * 1000);
$endDate = new MongoDB\BSON\UTCDateTime(strtotime('2024-01-31') * 1000);

$dateRangeResult = $batchDelete->deleteByDateRange('logs', 'created_at', $startDate, $endDate);
print_r($dateRangeResult);

// 删除旧文档
$cutoffDate = new MongoDB\BSON\UTCDateTime((time() - 90 * 86400) * 1000); // 90天前
$oldDocsResult = $batchDelete->deleteOldDocuments('logs', 'created_at', $cutoffDate);
print_r($oldDocsResult);
?>

查找并删除原理

使用findOneAndDelete()方法查找并删除文档:

php
<?php
// 查找并删除详解
class FindAndDelete {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    public function findOneAndDelete($collectionName, $filter, $options = []) {
        $collection = $this->database->selectCollection($collectionName);
        
        try {
            $defaultOptions = [
                'projection' => null,
                'sort' => null,
                'writeConcern' => null
            ];
            
            $deleteOptions = array_merge($defaultOptions, $options);
            
            $document = $collection->findOneAndDelete($filter, $deleteOptions);
            
            if ($document) {
                return [
                    'success' => true,
                    'deleted_document' => $document,
                    'deleted' => true
                ];
            } else {
                return [
                    'success' => true,
                    'deleted_document' => null,
                    'deleted' => false,
                    'message' => 'No document found matching the filter'
                ];
            }
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Find and delete failed',
                'message' => $e->getMessage()
            ];
        }
    }
    
    public function findOneAndDeleteWithSort($collectionName, $filter, $sort) {
        $collection = $this->database->selectCollection($collectionName);
        
        try {
            $document = $collection->findOneAndDelete($filter, ['sort' => $sort]);
            
            if ($document) {
                return [
                    'success' => true,
                    'deleted_document' => $document,
                    'sort_applied' => $sort
                ];
            } else {
                return [
                    'success' => true,
                    'deleted_document' => null,
                    'message' => 'No document found'
                ];
            }
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Find and delete with sort failed',
                'message' => $e->getMessage()
            ];
        }
    }
    
    public function findOneAndDeleteWithProjection($collectionName, $filter, $projection) {
        $collection = $this->database->selectCollection($collectionName);
        
        try {
            $document = $collection->findOneAndDelete($filter, ['projection' => $projection]);
            
            if ($document) {
                return [
                    'success' => true,
                    'deleted_document' => $document,
                    'projection_applied' => $projection
                ];
            } else {
                return [
                    'success' => true,
                    'deleted_document' => null,
                    'message' => 'No document found'
                ];
            }
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Find and delete with projection failed',
                'message' => $e->getMessage()
            ];
        }
    }
}

// 使用示例
$findAndDelete = new FindAndDelete('testdb');

// 基本查找并删除
$result = $findAndDelete->findOneAndDelete('users', ['email' => 'john@example.com']);
print_r($result);

// 带排序的查找并删除
$sort = ['created_at' => -1];
$sortResult = $findAndDelete->findOneAndDeleteWithSort('users', ['status' => 'pending'], $sort);
print_r($sortResult);

// 带投影的查找并删除
$projection = ['name' => 1, 'email' => 1, 'status' => 1];
$projectionResult = $findAndDelete->findOneAndDeleteWithProjection('users', ['status' => 'inactive'], $projection);
print_r($projectionResult);
?>

常见错误与踩坑点

错误1:删除条件不精确

问题描述:删除条件不够精确导致误删文档。

php
<?php
// 错误示例 - 删除条件不精确
try {
    $client = new MongoDB\Client("mongodb://localhost:27017");
    $database = $client->selectDatabase("testdb");
    $collection = $database->selectCollection('users');
    
    // 错误:删除条件不够精确
    $collection->deleteMany(['name' => 'John']);
    
    echo "Deleted all users named John\n";
    
} catch (Exception $e) {
    echo "错误: " . $e->getMessage() . "\n";
}

// 正确示例 - 使用精确的删除条件
$client = new MongoDB\Client("mongodb://localhost:27017");
$database = $client->selectDatabase("testdb");
$collection = $database->selectCollection('users');

// 正确:使用多个条件确保精确删除
$collection->deleteMany([
    'name' => 'John',
    'email' => 'john@example.com',
    'status' => 'inactive'
]);

echo "Deleted specific user with precise conditions\n";

// 或者先查找再删除
$document = $collection->findOne([
    'name' => 'John',
    'email' => 'john@example.com'
]);

if ($document) {
    $collection->deleteOne(['_id' => $document['_id']]);
    echo "Deleted specific user by ID\n";
}
?>

错误2:删除前未备份数据

问题描述:删除重要数据前未备份导致数据丢失。

php
<?php
// 错误示例 - 删除前未备份
try {
    $client = new MongoDB\Client("mongodb://localhost:27017");
    $database = $client->selectDatabase("testdb");
    $collection = $database->selectCollection('users');
    
    // 错误:直接删除未备份
    $collection->deleteMany(['status' => 'inactive']);
    
    echo "Deleted inactive users without backup\n";
    
} catch (Exception $e) {
    echo "错误: " . $e->getMessage() . "\n";
}

// 正确示例 - 删除前备份数据
$client = new MongoDB\Client("mongodb://localhost:27017");
$database = $client->selectDatabase("testdb");
$collection = $database->selectCollection('users');

// 正确:先备份数据
$documentsToBackup = $collection->find(['status' => 'inactive'])->toArray();

if (!empty($documentsToBackup)) {
    // 创建备份集合
    $backupCollection = $database->selectCollection('users_backup_' . date('YmdHis'));
    $backupCollection->insertMany($documentsToBackup);
    
    echo "Backed up " . count($documentsToBackup) . " documents\n";
    
    // 删除原始数据
    $result = $collection->deleteMany(['status' => 'inactive']);
    echo "Deleted " . $result->getDeletedCount() . " documents\n";
} else {
    echo "No documents to backup and delete\n";
}
?>

错误3:批量删除导致性能问题

问题描述:一次性删除大量文档导致性能问题。

php
<?php
// 错误示例 - 批量删除导致性能问题
try {
    $client = new MongoDB\Client("mongodb://localhost:27017");
    $database = $client->selectDatabase("testdb");
    $collection = $database->selectCollection('logs');
    
    // 错误:一次性删除大量文档
    $result = $collection->deleteMany(['created_at' => ['$lt' => new MongoDB\BSON\UTCDateTime((time() - 365 * 86400) * 1000)]]);
    
    echo "Deleted " . $result->getDeletedCount() . " documents\n";
    
} catch (Exception $e) {
    echo "错误: " . $e->getMessage() . "\n";
}

// 正确示例 - 分批删除大量文档
$client = new MongoDB\Client("mongodb://localhost:27017");
$database = $client->selectDatabase("testdb");
$collection = $database->selectCollection('logs');

// 正确:分批删除
$batchSize = 10000;
$totalDeleted = 0;
$batchCount = 0;

while (true) {
    $result = $collection->deleteMany(
        ['created_at' => ['$lt' => new MongoDB\BSON\UTCDateTime((time() - 365 * 86400) * 1000)]],
        ['limit' => $batchSize]
    );
    
    $deletedCount = $result->getDeletedCount();
    $totalDeleted += $deletedCount;
    $batchCount++;
    
    echo "Batch {$batchCount}: Deleted {$deletedCount} documents\n";
    
    if ($deletedCount === 0) {
        break;
    }
    
    // 短暂暂停,避免过载
    usleep(100000); // 100ms
}

echo "Total deleted: {$totalDeleted} documents in {$batchCount} batches\n";
?>

常见应用场景

场景1:软删除系统

实现软删除功能,保留删除记录:

php
<?php
// 软删除系统
class SoftDeleteSystem {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    public function softDelete($collectionName, $filter, $deletedBy = null) {
        $collection = $this->database->selectCollection($collectionName);
        
        try {
            $update = [
                '$set' => [
                    'deleted' => true,
                    'deleted_at' => new MongoDB\BSON\UTCDateTime(),
                    'deleted_by' => $deletedBy
                ]
            ];
            
            $result = $collection->updateMany($filter, $update);
            
            return [
                'success' => true,
                'soft_deleted' => true,
                'modified_count' => $result->getModifiedCount(),
                'deleted_by' => $deletedBy
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Soft delete failed',
                'message' => $e->getMessage()
            ];
        }
    }
    
    public function restoreSoftDeleted($collectionName, $filter) {
        $collection = $this->database->selectCollection($collectionName);
        
        try {
            $update = [
                '$unset' => ['deleted' => 1, 'deleted_at' => 1, 'deleted_by' => 1]
            ];
            
            $result = $collection->updateMany($filter, $update);
            
            return [
                'success' => true,
                'restored' => true,
                'modified_count' => $result->getModifiedCount()
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Restore failed',
                'message' => $e->getMessage()
            ];
        }
    }
    
    public function permanentlyDeleteSoftDeleted($collectionName, $filter) {
        $collection = $this->database->selectCollection($collectionName);
        
        try {
            $deleteFilter = array_merge($filter, ['deleted' => true]);
            $result = $collection->deleteMany($deleteFilter);
            
            return [
                'success' => true,
                'permanently_deleted' => true,
                'deleted_count' => $result->getDeletedCount()
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Permanent delete failed',
                'message' => $e->getMessage()
            ];
        }
    }
    
    public function getSoftDeletedDocuments($collectionName, $filter = [], $options = []) {
        $collection = $this->database->selectCollection($collectionName);
        
        try {
            $deleteFilter = array_merge($filter, ['deleted' => true]);
            
            $defaultOptions = [
                'sort' => ['deleted_at' => -1],
                'limit' => 100
            ];
            
            $queryOptions = array_merge($defaultOptions, $options);
            
            $cursor = $collection->find($deleteFilter, $queryOptions);
            $documents = iterator_to_array($cursor);
            
            return [
                'success' => true,
                'count' => count($documents),
                'documents' => $documents
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Query failed',
                'message' => $e->getMessage()
            ];
        }
    }
}

// 使用示例
$softDeleteSystem = new SoftDeleteSystem('testdb');

// 软删除文档
$softDeleteResult = $softDeleteSystem->softDelete(
    'users',
    ['status' => 'inactive'],
    'admin_user'
);
print_r($softDeleteResult);

// 恢复软删除的文档
$restoreResult = $softDeleteSystem->restoreSoftDeleted('users', ['email' => 'john@example.com']);
print_r($restoreResult);

// 永久删除软删除的文档
$permanentDeleteResult = $softDeleteSystem->permanentlyDeleteSoftDeleted('users', ['deleted' => true]);
print_r($permanentDeleteResult);

// 获取软删除的文档
$softDeletedDocs = $softDeleteSystem->getSoftDeletedDocuments('users', [], ['limit' => 10]);
print_r($softDeletedDocs);
?>

场景2:数据清理系统

实现自动数据清理功能:

php
<?php
// 数据清理系统
class DataCleanupSystem {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    public function cleanupOldLogs($collectionName, $retentionDays, $batchSize = 10000) {
        $collection = $this->database->selectCollection($collectionName);
        
        try {
            $cutoffDate = new MongoDB\BSON\UTCDateTime((time() - $retentionDays * 86400) * 1000);
            
            $totalDeleted = 0;
            $batchCount = 0;
            
            while (true) {
                $result = $collection->deleteMany(
                    ['created_at' => ['$lt' => $cutoffDate]],
                    ['limit' => $batchSize]
                );
                
                $deletedCount = $result->getDeletedCount();
                $totalDeleted += $deletedCount;
                $batchCount++;
                
                echo "Batch {$batchCount}: Deleted {$deletedCount} old logs\n";
                
                if ($deletedCount === 0) {
                    break;
                }
                
                // 短暂暂停
                usleep(100000);
            }
            
            return [
                'success' => true,
                'retention_days' => $retentionDays,
                'cutoff_date' => $cutoffDate->toDateTime()->format('Y-m-d H:i:s'),
                'total_deleted' => $totalDeleted,
                'batch_count' => $batchCount
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Log cleanup failed',
                'message' => $e->getMessage()
            ];
        }
    }
    
    public function cleanupExpiredSessions($collectionName) {
        $collection = $this->database->selectCollection($collectionName);
        
        try {
            $cutoffDate = new MongoDB\BSON\UTCDateTime((time() - 3600) * 1000); // 1小时前
            
            $result = $collection->deleteMany([
                'last_activity' => ['$lt' => $cutoffDate]
            ]);
            
            return [
                'success' => true,
                'expired_sessions_deleted' => $result->getDeletedCount(),
                'cutoff_date' => $cutoffDate->toDateTime()->format('Y-m-d H:i:s')
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Session cleanup failed',
                'message' => $e->getMessage()
            ];
        }
    }
    
    public function cleanupOrphanedDocuments($collectionName, $referenceField, $referenceCollectionName) {
        $collection = $this->database->selectCollection($collectionName);
        $referenceCollection = $this->database->selectCollection($referenceCollectionName);
        
        try {
            // 获取所有引用的ID
            $referencedIds = [];
            $cursor = $referenceCollection->find([], ['projection' => ['_id' => 1]]);
            
            foreach ($cursor as $document) {
                $referencedIds[] = $document['_id'];
            }
            
            // 删除没有引用的文档
            $result = $collection->deleteMany([
                $referenceField => ['$nin' => $referencedIds]
            ]);
            
            return [
                'success' => true,
                'orphaned_documents_deleted' => $result->getDeletedCount(),
                'reference_field' => $referenceField,
                'reference_collection' => $referenceCollectionName
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'Orphaned document cleanup failed',
                'message' => $e->getMessage()
            ];
        }
    }
}

// 使用示例
$dataCleanupSystem = new DataCleanupSystem('testdb');

// 清理旧日志
$logCleanupResult = $dataCleanupSystem->cleanupOldLogs('logs', 30);
print_r($logCleanupResult);

// 清理过期会话
$sessionCleanupResult = $dataCleanupSystem->cleanupExpiredSessions('sessions');
print_r($sessionCleanupResult);

// 清理孤立文档
$orphanCleanupResult = $dataCleanupSystem->cleanupOrphanedDocuments('comments', 'user_id', 'users');
print_r($orphanCleanupResult);
?>

常见问题答疑

问题1:如何安全地删除数据?

回答:通过备份、验证、分批删除等方式确保安全删除:

php
<?php
// 安全删除助手
class SafeDeleteHelper {
    public static function safeDelete($collection, $filter, $options = []) {
        $backupBeforeDelete = $options['backup'] ?? true;
        $verifyBeforeDelete = $options['verify'] ?? true;
        $batchDelete = $options['batch'] ?? false;
        
        if ($backupBeforeDelete) {
            // 备份数据
            $documents = $collection->find($filter)->toArray();
            if (!empty($documents)) {
                $backupCollection = $collection->getDatabase()->selectCollection(
                    $collection->getCollectionName() . '_backup_' . date('YmdHis')
                );
                $backupCollection->insertMany($documents);
            }
        }
        
        if ($verifyBeforeDelete) {
            // 验证删除条件
            $count = $collection->countDocuments($filter);
            if ($count === 0) {
                return [
                    'success' => false,
                    'message' => 'No documents match the filter'
                ];
            }
        }
        
        // 执行删除
        if ($batchDelete) {
            $result = $collection->deleteMany($filter, ['limit' => $options['batch_size'] ?? 10000]);
        } else {
            $result = $collection->deleteMany($filter);
        }
        
        return [
            'success' => true,
            'deleted_count' => $result->getDeletedCount(),
            'backup_created' => $backupBeforeDelete,
            'verified' => $verifyBeforeDelete
        ];
    }
}

// 使用示例
$client = new MongoDB\Client("mongodb://localhost:27017");
$database = $client->selectDatabase("testdb");
$collection = $database->selectCollection('users');

$safeResult = SafeDeleteHelper::safeDelete(
    $collection,
    ['status' => 'inactive'],
    ['backup' => true, 'verify' => true, 'batch' => true, 'batch_size' => 1000]
);
print_r($safeResult);
?>

实战练习

练习1:实现用户删除系统

实现一个完整的用户删除系统:

php
<?php
// 用户删除系统
class UserDeleteSystem {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    public function deleteUser($userId, $deleteOptions = []) {
        $collection = $this->database->selectCollection('users');
        
        try {
            // 检查用户是否存在
            $user = $collection->findOne(['_id' => new MongoDB\BSON\ObjectId($userId)]);
            
            if (!$user) {
                return [
                    'success' => false,
                    'message' => 'User not found'
                ];
            }
            
            // 备份用户数据
            if ($deleteOptions['backup'] ?? true) {
                $backupCollection = $this->database->selectCollection('users_deleted_backup');
                $backupCollection->insertOne($user);
            }
            
            // 删除用户
            $result = $collection->deleteOne(['_id' => new MongoDB\BSON\ObjectId($userId)]);
            
            return [
                'success' => true,
                'user_id' => $userId,
                'deleted_count' => $result->getDeletedCount(),
                'backup_created' => $deleteOptions['backup'] ?? true
            ];
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => 'User deletion failed',
                'message' => $e->getMessage()
            ];
        }
    }
    
    public function batchDeleteUsers($userIds, $deleteOptions = []) {
        $collection = $this->database->selectCollection('users');
        
        $results = [
            'total_users' => count($userIds),
            'deleted_users' => 0,
            'failed_users' => 0,
            'details' => []
        ];
        
        foreach ($userIds as $userId) {
            $result = $this->deleteUser($userId, $deleteOptions);
            
            if ($result['success']) {
                $results['deleted_users']++;
            } else {
                $results['failed_users']++;
            }
            
            $results['details'][] = [
                'user_id' => $userId,
                'result' => $result
            ];
        }
        
        return $results;
    }
}

// 使用示例
$userDeleteSystem = new UserDeleteSystem('user_db');

// 删除单个用户
$deleteResult = $userDeleteSystem->deleteUser('507f1f77bcf86cd799439011', ['backup' => true]);
print_r($deleteResult);

// 批量删除用户
$userIds = [
    '507f1f77bcf86cd799439011',
    '507f1f77bcf86cd799439012',
    '507f1f77bcf86cd799439013'
];

$batchDeleteResult = $userDeleteSystem->batchDeleteUsers($userIds, ['backup' => true]);
print_r($batchDeleteResult);
?>

知识点总结

核心概念

  1. 删除方法deleteOne()deleteMany()findOneAndDelete()
  2. 删除策略:精确删除、范围删除、批量删除
  3. 删除选项:writeConcern、collation、hint
  4. 删除性能:索引优化、分批删除、条件优化

删除方法

  1. deleteOne():删除单个文档
  2. deleteMany():删除多个文档
  3. findOneAndDelete():查找并删除单个文档
  4. bulkWrite():批量执行删除操作

最佳实践

  1. 精确删除:使用精确的删除条件
  2. 数据备份:删除前备份重要数据
  3. 分批删除:大量数据分批删除
  4. 软删除:使用标记代替物理删除

常见场景

  1. 用户删除:删除用户及其相关数据
  2. 数据清理:定期清理过期数据
  3. 软删除:使用deleted标记
  4. 批量删除:删除符合条件的大量数据

拓展参考资料

官方文档

推荐阅读

  • 《MongoDB数据清理实践》
  • 《MongoDB软删除实现》
  • 《MongoDB删除操作优化》

在线资源

  • MongoDB University删除操作课程
  • MongoDB官方博客数据管理文章
  • Stack Overflow MongoDB删除相关问题