我有一个包含任务的Couch数据库。这些任务可以分别有多个注释。我想要一个视图,它返回所有任务,每个任务只有一个最新的评论。
将其视为获取所有博客帖子以及每篇帖子的最新评论。
这是可能的吗?答案 0 :(得分:0)
哦,你有选择!最有效的将在很大程度上取决于您的用例。
在这种方法中,客户端获取所有信息并决定要显示的内容。您可以从显示最新评论开始,如果用户想要查看更多评论,它将是即时的 - 没有更多请求,因为您已经收到了数据!
评论示例:
{
"_id": "89f34369f0a50685bcb0682103003b2d",
"_rev": "1-f64ffb6e374b8055b2fcdaa040f26a4f",
"taskId": "89f34369f0a50685bcb0682103002037",
"text": "use the tire pressure in the driver's side door jamb",
"type": "comment",
"timestamp": 300
}
示例任务:
{
"_id": "89f34369f0a50685bcb0682103002037",
"_rev": "1-6249079866249429dc35ba113d4772de",
"type": "task",
"text": "check tire pressure"
}
查看以向您提供任务和评论:
{
"_id": "_design/mydesign",
"_rev": "1-3ac9fa693c8b20f9598a4c667009ed45",
"views": {
"tasks_with_most_recent_comment": {
"map": "function(doc) { if(doc.type === 'task') { emit([doc._id, 0], doc); } else if (doc.type === 'comment') { emit([doc.taskId, 1], doc); } }"
}
}
}
在结果中,所有评论都有key[1] === 0
,而所有评论都有key[1] === 1
。
如果我有一个阅读量大的应用程序,收到很多评论,我会考虑将评论建模为一个单独的文档,并将最新的评论嵌入到任务中。
评论示例:
{
"_id": "89f34369f0a50685bcb0682103003b2d",
"_rev": "1-f64ffb6e374b8055b2fcdaa040f26a4f",
"taskId": "89f34369f0a50685bcb0682103002037",
"text": "use the tire pressure in the driver's side door jamb",
"type": "comment",
"timestamp": 300
}
示例任务:
{
"_id": "89f34369f0a50685bcb0682103002037",
"_rev": "1-6249079866249429dc35ba113d4772de",
"type": "task",
"text": "check tire pressure",
"mostRecentComment": {
"_id": "89f34369f0a50685bcb0682103003b2d",
"_rev": "1-f64ffb6e374b8055b2fcdaa040f26a4f",
"taskId": "89f34369f0a50685bcb0682103002037",
"text": "use the tire pressure in the driver's side door jamb",
"type": "comment",
"timestamp": 300
}
}
在这种方法中,获取最新的注释是在写入时处理的,因此检索它的查询非常简单。
如果评论很少,也许将它们全部嵌入到这样的任务中是有意义的:
{
"_id": "89f34369f0a50685bcb0682103000640",
"_rev": "1-5fb40b1d24bdbacbbb652112dfb3e3e5",
"text": "pick up milk",
"comments": [
{ "timestamp": 100000000, "text": "first" },
{ "timestamp": 900000000, "text": "last" },
{ "timestamp": 800000000, "text": "middle" }
]
}
只提取最新的合理方法是按时间戳按降序排序doc.comments
,然后抓住第一个。
我们不能这样做,因为views cannot update documents;他们必须是无副作用的。因此,虽然简单地用比较器调用doc.comments.sort
是很诱人的,但是会尝试sort in place,改变comments数组,并抛出错误:
Log :: function raised exception (new TypeError("doc.comments.sort(function (a, b) {return b.timestamp - a.timestamp;}) is read-only", "undefined", 1)) with doc._id 89f34369f0a50685bcb0682103000640
相反,我们可以调用slice来为我们提供数组的浅表副本。
var recentComments = doc.comments.slice() // new array we're free to modify
.sort(function(a, b) { // sort in place
return b.timestamp - a.timestamp; // descending order by timestamp
}).slice(0,1); // take only the first result as an array
所以现在我们有一个只有最新评论的评论数组。我们已经知道我们无法重新分配它,所以让我们构建另一个对象来提供我们的emit
函数。请注意,新对象应包含您关注的所有字段。
emit(doc._id, {text: doc.text, comments: recentComments});
所有这些让我们最终了解:
{
"_id": "_design/mydesign",
"_rev": "1-be95f2e2a699bb7182184dbc0729d3ce",
"views": {
"task_with_most_recent_comment": {
"map": "function(doc){ emit(doc._id, {text: doc.text, comments: doc.comments.slice().sort(function(a, b) { return b.timestamp - a.timestamp; }).slice(0,1) }); }}"
}
}
}