Skip to content

CouchDB - 更新文档

在 CouchDB 中,文档不会原地修改。相反,更新文档意味着创建它的一个新版本。这个过程是 CouchDB 多版本并发控制(MVCC)模型的基础,它能防止在分布式或高并发环境中发生数据丢失。

CouchDB 中的每个文档都有一个 _id(其唯一标识符)和一个 _rev(其版本号)。要更新文档,您必须提供您正在更新的版本对应的 _rev。如果您提供的 _rev 与数据库中当前的 _rev 匹配,您的更新将被接受,并创建一个带有新 _rev 的新版本。如果 _rev 不匹配,CouchDB 将以 409 Conflict 错误拒绝更新。此机制确保您不会意外覆盖由另一个进程所做的更改。

cURL 命令行工具非常适合测试和直接 API 交互。更新文档的工作流程分为两步:

步骤 1:获取当前文档以查找其 _rev

Section titled “步骤 1:获取当前文档以查找其 _rev”

假设我们的 profiles 数据库中有一个 ID 为 user123 的用户档案。

# 请求
$ curl -X GET http://127.0.0.1:5984/profiles/user123
# 响应
{
"_id": "user123",
"_rev": "1-a954784578bca65545a1989467262913",
"name": "Alice",
"email": "alice@example.com",
"status": "active"
}

请注意 _rev 值:1-a954784578bca65545a1989467262913。

步骤 2:提交带有 _rev 的更新文档

Section titled “步骤 2:提交带有 _rev 的更新文档”

现在,我们将用户的状态更新为 inactive。我们必须包含整个文档体以及刚刚获取的 _rev。

# 请求
$ curl -X PUT http://127.0.0.1:5984/profiles/user123 -d \
'{
"_id": "user123",
"_rev": "1-a954784578bca65545a1989467262913",
"name": "Alice",
"email": "alice@example.com",
"status": "inactive"
}'
# 响应
{
"ok": true,
"id": "user123",
"rev": "2-d7b1372551421f5286f7887720c1e879"
}

成功!响应显示 "ok": true 并提供了新的版本号,它以 2- 开头。如果我们要再次更新文档,就需要使用这个新的 _rev。

编程式更新:使用 Node.js 和 Axios

Section titled “编程式更新:使用 Node.js 和 Axios”

在实际应用中,您将通过编程方式执行这些操作。这是一个使用 Node.js 和流行的 axios HTTP 客户端的完整示例。首先,请确保已安装 axios:npm install axios。

const axios = require('axios');
const dbUrl = 'http://127.0.0.1:5984/profiles';
const docId = 'user123';
async function updateUserStatus(newStatus) {
try {
// 步骤 1:获取最新文档以获取当前的 _rev
console.log(`Fetching document: ${docId}`);
const getResponse = await axios.get(`${dbUrl}/${docId}`);
const document = getResponse.data;
console.log(`Current revision is: ${document._rev}`);
// 步骤 2:修改文档并准备更新负载
const updatedDocument = {
...document, // 复制所有现有字段
status: newStatus, // 覆盖 status 字段
updatedAt: new Date().toISOString() // 添加新字段
};
// _rev 已经在文档对象中,因此我们不需要再次添加它。
// 步骤 3:将更新后的文档 PUT 回数据库
console.log(`Updating document with status: ${newStatus}`);
const putResponse = await axios.put(`${dbUrl}/${docId}`, updatedDocument);
console.log('Update successful!');
console.log('New revision:', putResponse.data.rev);
return putResponse.data;
} catch (error) {
// 处理潜在错误
if (error.response) {
console.error(`Error: ${error.response.status} - ${error.response.data.reason}`);
if (error.response.status === 409) {
console.error('冲突:文档已被另一个进程更新。请重试该操作。');
}
} else {
console.error('An unexpected error occurred:', error.message);
}
return null;
}
}
// 运行更新函数
updateUserStatus('suspended');

Fauxton 是 CouchDB 现代内置的 Web 管理控制台。它提供了一种用户友好的方式来管理文档。(可通过 http://127.0.0.1:5984/_utils/ 访问)

  1. 导航到您的数据库:从 Fauxton 主仪表板,点击左侧的“Databases”(数据库)图标,然后从列表中选择您的数据库(例如,profiles)。
  2. 选择文档:数据库中的文档列表将出现。点击您希望更新的文档的 _id(例如,user123)。
  3. 编辑文档:文档内容将以可编辑的 JSON 格式显示在文本编辑器中。您可以直接修改字段的值。例如,将 "status" 的值从 "active" 更改为 "inactive"。
  4. 保存更改:点击绿色的“Save Document”(保存文档)按钮。Fauxton 会自动处理获取最新的 _rev 并将其包含在更新请求中,使整个过程无缝且避免冲突。
  • 处理 409 Conflict 冲突: 这不是一个错误;它是一个特性。您的应用程序逻辑必须做好处理它的准备。正确的策略是捕获 409 错误,重新获取文档以获取新的 _rev,然后在再次尝试 PUT 请求之前重新应用您的更改。
  • 批量更新: 如果您需要一次更新许多文档,请不要为每个文档发送一个请求。这是低效的。相反,请使用 _bulk_docs 端点在单个 HTTP 请求中发送一批更新的文档,以显著提高性能。
  • 切勿硬编码 _rev: 文档的版本是动态的。切勿在应用程序代码中硬编码 _rev 值。在您打算执行更新之前,请务必获取最新的 _rev。