赞
踩
{"id": "","username": ""}
id作为分区的id,那意味着每一个逻辑分区仅包含一个用户。
{"id": "","type": "post","postId": "","userId": "","title": "","content": "","creationDate": ""}{"id": "","type": "comment","postId": "","userId": "","content": "","creationDate": ""}{"id": "","type": "like","postId": "","userId": "","creationDate": ""}
我们以postId作为分区ID,那意味着容器内每个逻辑分区将包含一个post,该帖子的所有评论和点赞信息。上篇文章,我们介绍了使用type来区分不同的实体,在该容器里使用了三种类型。而且,我们也选择了引用数据来替代嵌入数据,因为
{"id": "","type": "post","postId": "","userId": "","userUsername": "","title": "","content": "","commentCount": ,"likeCount": ,"creationDate": ""}
我们也修改了评论和点赞这两个数据项,增加了发表评论和点赞者的用户名。
{"id": "","type": "comment","postId": "","userId": "","userUsername": "","content": "","creationDate": ""}{"id": "","type": "like","postId": "","userId": "","userUsername": "","creationDate": ""}
function createComment(postId, comment) {var collection = getContext().getCollection(); collection.readDocument(`${collection.getAltLink()}/docs/${postId}`,function (err, post) {if (err) throw err; post.commentCount++; collection.replaceDocument( post._self, post,function (err) {if (err) throw err; comment.postId = postId; collection.createDocument( collection.getSelfLink(), comment ); } ); })}
这个存储过程使用post id和新的comment作为参数,接着
function updateUsernames(userId, username) {var collection = getContext().getCollection(); collection.queryDocuments( collection.getSelfLink(),`SELECT * FROM p WHERE p.userId = '${userId}'`,function (err, results) {if (err) throw err;for (var i in results) {var doc = results[i]; doc.userUsername = username; collection.upsertDocument( collection.getSelfLink(), doc); } });}
这个存储过程以user id和新的用户名作为参数,接着
重要
这个操作也是比较耗时操作,因为它要求这个存储过程被执行在posts容器的每个分区上。我们假定大部分用户很少改变用户名,所以这个更新应该很少被执行。
{"id": "","type": "user","userId": "","username": ""}{"id": "","type": "post","postId": "","userId": "","userUsername": "","title": "","content": "","commentCount": ,"likeCount": ,"creationDate": ""}
注意:现在我们可以查询users容器,按照容器的partition key来过滤。
我们添加了type字段来区分users和posts。我们也在user项目里增加了userId字段,那是冗余的和id字段,但现在我们就可以使用userId字段来作为partition key而不是id作为partiton key。为了实现这个非规范化,我们需要再次使用change feed。这次,我们发布任何新的或者更新post会激活posts容器的change feed,因为列举post不要求返回所有的内容,在这个过程中我们可以删除一些数据。
{"id": "","type": "post","postId": "","userId": "","userUsername": "","title": "","content": "","commentCount": ,"likeCount": ,"creationDate": ""}
这个容器以type作为partition key,在我们的项目中类型始终是post,这样确保所有的项目都在同一个分区中。为了实现这个非规范化,我们仅不得不使用change feed,当发布新帖子时触发此change feed。一个重要的事情是我们仅存储最近100条帖子,要不然,这个容器将会超过partition所允许的最大尺寸,我们可以在每次一个项目被新增时调用post-trigger来实现。
下面是post-trigger的实现。
function truncateFeed() {const maxDocs = 100;var context = getContext();var collection = context.getCollection(); collection.queryDocuments( collection.getSelfLink(),"SELECT VALUE COUNT(1) FROM f",function (err, results) {if (err) throw err; processCountResults(results); });function processCountResults(results) {// + 1 because the query didn't count the newly inserted docif ((results[0] + 1) > maxDocs) {var docsToRemove = results[0] + 1 - maxDocs; collection.queryDocuments( collection.getSelfLink(),`SELECT TOP ${docsToRemove} * FROM f ORDER BY f.creationDate`,function (err, results) {if (err) throw err; processDocsToRemove(results, 0); }); } }function processDocsToRemove(results, index) {var doc = results[index];if (doc) { collection.deleteDocument( doc._self,function (err) {if (err) throw err; processDocsToRemove(results, index + 1); }); } }}
最后一步来查看优化后的性能。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。