Couchbase文档删除 #
一、概述 #
1.1 删除方式 #
Couchbase提供多种文档删除方式:
| 方式 | 说明 | 使用场景 |
|---|---|---|
| DELETE | N1QL删除语句 | 条件删除、批量删除 |
| remove() | SDK删除方法 | 单个文档删除 |
| 软删除 | 标记删除状态 | 需要保留历史记录 |
1.2 删除注意事项 #
text
删除前请注意:
1. 删除操作不可恢复(除非有备份)
2. 删除会释放内存和磁盘空间
3. 删除后索引会自动更新
4. 考虑使用软删除保留历史
二、DELETE语句 #
2.1 基本语法 #
sql
DELETE FROM `keyspace`
WHERE condition;
2.2 删除单个文档 #
sql
DELETE FROM `my-bucket`.`_default`.`_default`
WHERE META().id = 'user::001';
DELETE FROM `my-bucket`.`_default`.`_default`
WHERE type = 'user' AND email = 'test@example.com';
2.3 使用RETURNING #
sql
DELETE FROM `my-bucket`.`_default`.`_default`
WHERE META().id = 'user::001'
RETURNING META().id AS deleted_id, *;
2.4 条件删除 #
sql
DELETE FROM `my-bucket`.`_default`.`_default`
WHERE type = 'user' AND status = 'inactive';
DELETE FROM `my-bucket`.`_default`.`_default`
WHERE type = 'session'
AND created_at < DATE_ADD_STR(NOW_STR(), -7, 'day');
DELETE FROM `my-bucket`.`_default`.`_default`
WHERE type = 'log' AND level = 'debug';
2.5 使用USE KEYS #
sql
DELETE FROM `my-bucket`.`_default`.`_default`
USE KEYS 'user::001';
DELETE FROM `my-bucket`.`_default`.`_default`
USE KEYS ['user::001', 'user::002', 'user::003'];
三、批量删除 #
3.1 删除所有匹配文档 #
sql
DELETE FROM `my-bucket`.`_default`.`_default`
WHERE type = 'temp_data';
DELETE FROM `my-bucket`.`_default`.`_default`
WHERE type = 'cache' AND expires_at < NOW_STR();
3.2 限制删除数量 #
sql
DELETE FROM `my-bucket`.`_default`.`_default`
WHERE type = 'log'
LIMIT 1000;
3.3 使用子查询删除 #
sql
DELETE FROM `my-bucket`.`_default`.`_default` AS o
WHERE o.type = 'order'
AND o.user_id IN (
SELECT META().id
FROM `my-bucket`.`_default`.`_default`
WHERE type = 'user' AND status = 'deleted'
);
3.4 分批删除 #
python
import time
def batch_delete(collection, batch_size=1000):
while True:
result = cluster.query('''
DELETE FROM `my-bucket`.`_default`.`_default`
WHERE type = 'temp_data'
LIMIT $batch_size
RETURNING META().id
''', QueryOptions(named_parameters={'batch_size': batch_size}))
deleted_count = len(list(result.rows()))
if deleted_count == 0:
break
print(f'已删除 {deleted_count} 条记录')
time.sleep(0.1)
四、SDK删除操作 #
4.1 Python SDK #
python
from couchbase.cluster import Cluster, ClusterOptions
from couchbase.auth import PasswordAuthenticator
from couchbase.options import RemoveOptions
from couchbase.exceptions import DocumentNotFoundException, CasMismatchException
cluster = Cluster(
'couchbase://localhost',
ClusterOptions(PasswordAuthenticator('Administrator', 'password'))
)
bucket = cluster.bucket('my-bucket')
collection = bucket.default_collection()
collection.remove('user::001')
try:
result = collection.get('user::001')
collection.remove('user::001', RemoveOptions(cas=result.cas))
except DocumentNotFoundException:
print('文档不存在')
except CasMismatchException:
print('文档已被修改')
try:
collection.remove('user::999')
except DocumentNotFoundException:
print('文档不存在')
4.2 Node.js SDK #
javascript
const couchbase = require('couchbase');
const cluster = new couchbase.Cluster('couchbase://localhost', {
username: 'Administrator',
password: 'password'
});
const bucket = cluster.bucket('my-bucket');
const collection = bucket.defaultCollection();
await collection.remove('user::001');
try {
const result = await collection.get('user::001');
await collection.remove('user::001', { cas: result.cas });
} catch (error) {
if (error instanceof couchbase.DocumentNotFoundError) {
console.log('文档不存在');
} else if (error instanceof couchbase.CasMismatchError) {
console.log('文档已被修改');
}
}
try {
await collection.remove('user::999');
} catch (error) {
if (error instanceof couchbase.DocumentNotFoundError) {
console.log('文档不存在');
}
}
4.3 Java SDK #
java
import com.couchbase.client.java.*;
import com.couchbase.client.java.kv.*;
import com.couchbase.client.java.exceptions.*;
Cluster cluster = Cluster.connect(
"localhost",
ClusterOptions.clusterOptions("Administrator", "password")
);
Bucket bucket = cluster.bucket("my-bucket");
Collection collection = bucket.defaultCollection();
collection.remove("user::001");
try {
GetResult result = collection.get("user::001");
collection.remove(
"user::001",
RemoveOptions.removeOptions().cas(result.cas())
);
} catch (DocumentNotFoundException e) {
System.out.println("文档不存在");
} catch (CasMismatchException e) {
System.out.println("文档已被修改");
}
try {
collection.remove("user::999");
} catch (DocumentNotFoundException e) {
System.out.println("文档不存在");
}
五、软删除 #
5.1 软删除概念 #
软删除不是真正删除文档,而是标记删除状态:
json
{
"type": "user",
"name": "张三",
"email": "zhangsan@example.com",
"deleted": true,
"deleted_at": "2024-01-20T15:00:00Z"
}
5.2 实现软删除 #
sql
UPDATE `my-bucket`.`_default`.`_default`
SET
deleted = true,
deleted_at = NOW_STR(),
status = 'deleted'
WHERE type = 'user' AND META().id = 'user::001';
5.3 查询时排除已删除 #
sql
SELECT * FROM `my-bucket`.`_default`.`_default`
WHERE type = 'user' AND (deleted = false OR deleted IS MISSING);
CREATE INDEX idx_users_active
ON `my-bucket`.`_default`.`_default`(name)
WHERE type = 'user' AND (deleted = false OR deleted IS MISSING);
5.4 恢复软删除 #
sql
UPDATE `my-bucket`.`_default`.`_default`
SET
deleted = false,
deleted_at = null,
status = 'active',
restored_at = NOW_STR()
WHERE type = 'user' AND META().id = 'user::001';
5.5 永久删除软删除数据 #
sql
DELETE FROM `my-bucket`.`_default`.`_default`
WHERE deleted = true
AND deleted_at < DATE_ADD_STR(NOW_STR(), -30, 'day');
六、级联删除 #
6.1 删除关联文档 #
sql
DELETE FROM `my-bucket`.`_default`.`_default` AS d
WHERE d.type = 'order_item'
AND d.order_id = 'order::001';
DELETE FROM `my-bucket`.`_default`.`_default`
WHERE type = 'order' AND META().id = 'order::001';
6.2 使用事务级联删除 #
python
from couchbase.transactions import Transactions
from couchbase.transactions.config import TransactionsConfig
transactions = Transactions(cluster, TransactionsConfig())
def delete_order_with_items(order_id):
def txn_logic(ctx):
ctx.remove(ctx.get(collection, order_id))
items = cluster.query('''
SELECT META().id
FROM `my-bucket`.`_default`.`_default`
WHERE type = 'order_item' AND order_id = $order_id
''', QueryOptions(named_parameters={'order_id': order_id}))
for item in items.rows():
ctx.remove(ctx.get(collection, item['id']))
transactions.run(txn_logic)
七、过期自动删除 #
7.1 设置文档过期 #
sql
INSERT INTO `my-bucket`.`_default`.`_default` (KEY, VALUE, OPTIONS)
VALUES (
'session::abc123',
{'user_id': 'user::001', 'token': 'abc123'},
{'expiration': 3600}
);
7.2 SDK设置过期 #
python
from datetime import timedelta
from couchbase.options import UpsertOptions
collection.upsert(
'session::abc123',
{'user_id': 'user::001', 'token': 'abc123'},
UpsertOptions(expiry=timedelta(hours=1))
)
collection.get_and_touch('session::abc123', timedelta(hours=2))
7.3 更新过期时间 #
python
collection.touch('session::abc123', timedelta(hours=1))
八、删除性能优化 #
8.1 使用索引加速删除 #
sql
CREATE INDEX idx_users_status
ON `my-bucket`.`_default`.`_default`(status)
WHERE type = 'user';
DELETE FROM `my-bucket`.`_default`.`_default`
WHERE type = 'user' AND status = 'inactive';
8.2 分批删除大量数据 #
python
def delete_in_batches(query, batch_size=1000):
total_deleted = 0
while True:
result = cluster.query(f'''
DELETE FROM `my-bucket`.`_default`.`_default`
WHERE {query}
LIMIT {batch_size}
RETURNING META().id
''')
deleted = list(result.rows())
if not deleted:
break
total_deleted += len(deleted)
print(f'已删除 {len(deleted)} 条,总计 {total_deleted} 条')
time.sleep(0.1)
return total_deleted
delete_in_batches("type = 'log' AND created_at < '2024-01-01'")
8.3 异步删除 #
python
import asyncio
from acouchbase.cluster import Cluster
async def async_delete(keys):
cluster = await Cluster.connect(
'couchbase://localhost',
ClusterOptions(PasswordAuthenticator('Administrator', 'password'))
)
bucket = cluster.bucket('my-bucket')
collection = bucket.default_collection()
tasks = [collection.remove(key) for key in keys]
await asyncio.gather(*tasks, return_exceptions=True)
asyncio.run(async_delete(['user::001', 'user::002', 'user::003']))
九、删除与索引 #
9.1 删除后索引更新 #
text
删除文档时:
1. 文档从Bucket中删除
2. 相关索引自动更新
3. 索引项被移除
注意:大量删除可能导致索引碎片化
9.2 索引维护 #
sql
BUILD INDEX ON `my-bucket`.`_default`.`_default`(idx_users_status);
ALTER INDEX idx_users_status
ON `my-bucket`.`_default`.`_default`
WITH {"action": "cleanup"};
十、常见错误处理 #
10.1 文档不存在 #
python
from couchbase.exceptions import DocumentNotFoundException
try:
collection.remove('user::999')
except DocumentNotFoundException:
print('文档不存在,无需删除')
10.2 CAS不匹配 #
python
from couchbase.exceptions import CasMismatchException
def remove_with_retry(key, max_retries=3):
for _ in range(max_retries):
try:
result = collection.get(key)
collection.remove(key, RemoveOptions(cas=result.cas))
return True
except CasMismatchException:
continue
except DocumentNotFoundException:
return True
return False
10.3 删除权限不足 #
python
from couchbase.exceptions import PermissionDeniedException
try:
collection.remove('admin::config')
except PermissionDeniedException:
print('没有删除权限')
十一、删除最佳实践 #
11.1 删除前备份 #
sql
INSERT INTO `my-bucket`.`_default`.`backup` (KEY, VALUE)
SELECT 'backup::' || META().id, _default
FROM `my-bucket`.`_default`.`_default`
WHERE type = 'user' AND status = 'inactive';
11.2 使用事务保证一致性 #
python
from couchbase.transactions import Transactions
def safe_delete_with_related(main_id):
def txn_logic(ctx):
ctx.remove(ctx.get(collection, main_id))
related = cluster.query('''
SELECT META().id
FROM `my-bucket`.`_default`.`_default`
WHERE related_id = $id
''', QueryOptions(named_parameters={'id': main_id}))
for item in related.rows():
ctx.remove(ctx.get(collection, item['id']))
transactions.run(txn_logic)
11.3 审计日志 #
python
def delete_with_audit(key, operator):
result = collection.get(key)
doc = result.content
audit_doc = {
'type': 'delete_audit',
'document_id': key,
'document_content': doc,
'operator': operator,
'deleted_at': NOW_STR()
}
collection.upsert(f'audit::delete::{key}::{NOW_STR()}', audit_doc)
collection.remove(key)
十二、总结 #
删除操作要点:
| 操作 | 说明 | 使用场景 |
|---|---|---|
| DELETE | N1QL删除 | 批量删除、条件删除 |
| remove() | SDK删除 | 单个文档删除 |
| 软删除 | 标记删除 | 需要保留历史 |
| 过期删除 | 自动清理 | 临时数据 |
最佳实践:
- 重要数据使用软删除
- 大量删除分批进行
- 删除前考虑备份
- 使用事务保证一致性
- 添加审计日志
下一步,让我们学习基础查询操作!
最后更新:2026-03-27