在CouchDB中向现有文档添加字段

2 投票
1 回答
6349 浏览
提问于 2025-04-18 07:22

我有一个数据库,里面存了一些普通的文档,长得像这样(这是个来自维基的例子):

{
 "_id":"some_doc_id",
 "_rev":"D1C946B7",
 "Subject":"I like Plankton",
 "Author":"Rusty",
 "PostedDate":"2006-08-15T17:30:12-04:00",
 "Tags":["plankton", "baseball", "decisions"],
 "Body":"I decided today that I don't like baseball. I like plankton."
}

我正在用Python和couchdb-python这个库工作,我想知道是否可以给每个文档添加一个字段。比如说,我想加一个“位置”字段之类的。

谢谢!

1 个回答

5

关于ID

在CouchDB中,每个文档都有一个ID,不管你是否自己设置。文档存储后,你可以通过 doc._id 字段来访问它。

如果你想自己设置ID,就需要把ID的值赋给 doc._id。如果不设置,CouchDB会自动生成一个 UUID

如果你想更新一个文档,必须确保你有相同的ID和有效的版本号。如果你在处理一个博客文章,用户添加了位置,那么文章的URL可能是一个不错的ID,这样你就能立刻访问到这个文档。

那么什么是版本

在你上面的代码片段中,有 doc._rev 这个元素。它是版本的标识符。如果你保存一个已经存在ID的文档,CouchDB会要求你证明这个文档仍然有效,并且你不是在覆盖别人的文档。

那么我怎么更新文档

如果你有文档的ID,可以通过使用 db.get(id) 函数来访问每个文档。然后你可以像这样更新文档:

doc = db.get(id)
doc['Location'] = "On a couch"
db.save(doc)

我有一个例子是存储天气预报数据。我大约每两小时更新一次预报。还有一个独立的进程在寻找我从不同提供者那里获取的数据,关注当天推文的特征。

这看起来像这样。

doc = db.get(id)
doc_with_loc = GetLocationInformationFromOtherProvider(doc) # takes about 40 seconds. 
doc_with_loc["_rev"]  = doc["_rev"]
db.save(doc_with_loc) # This will fail if weather update has also updated the file.

如果你有多个进程同时运行,_rev 会变得无效,所以你必须有一个安全措施,比如这样 可能 会做到:

doc = db.get(id)
doc_with_loc = GetLocationInformationFromAltProvider(doc)
update_outstanding = true
while update_outstanding:
    doc = db.get(id) //reretrieve this to get 
    doc_with_loc["_rev"]  = doc["_rev"]
    update_outstanding = !db.save(doc_with_loc)

那么我怎么获取ID?

上面提到的一个选项是你主动设置ID,这样你就可以检索到它。也就是说,如果用户设置了一个与URL相关的位置,就用这个URL。但你可能不知道想更新哪个文档,或者甚至有一个进程可以找到所有没有位置的文档并为它们分配一个。

你很可能会使用视图来实现这一点。视图有一个映射器和一个归约器。你会使用第一个,忘记第二个。带有映射器的视图做的事情是:

它返回一种简化/转换后的数据查看方式。你可以为每个数据返回多个值,或者跳过一些。它给你发出的数据一个键,如果你使用 _include_docs 函数,它会给你文档(同时包含 _idrev)。

最简单的视图是默认视图 db.view('_all_docs'),这将返回所有文档,而你可能不想更新所有文档。定义视图时,视图本身也会作为文档存储。

下一个简单的方法是创建一个只返回特定类型文档的视图。我通常在我的数据库中有 _type="article"。可以把它想象成如果你把文档存储在关系数据库中,就像标记文档属于某个表一样。

最后,你可以过滤出有位置的元素,这样你就会有一个视图,可以遍历所有仍需要位置的文档,并在一个单独的进程中识别它们。关于编写视图的最佳文档可以在 这里 找到。

撰写回答