《小白变大神,微信小程序云开发快速入门与成本控制实战》系列文章
第五篇:大幅降低微信小程序云数据库的调用次数和成本费用
在上一篇文章中,我们介绍了如何使用前端和来缓存用户数据,并通过缓存来减少调用次数的资源消耗。
但除了在前端中缓存数据,我们也需要把用户数据保存到云数据库中。
在本篇文章中,我们将详细介绍与相关的工具函数。当用户使用你的小程序时,经常需要保存用户的交互数据,例如用户修改了字体的大小、提交了一些文字、阅读了一些文章(需保存最近阅读列表)等等。
如果这些数据内容不是很多,可以使用相关函数把这些数据保存到数据库中,这有以下几个优点:
-
使用这些工具函数可以让你的小程序代码更加简洁,不需要自己写数据库操作的代码;
-
当你修改数据库中的数据时,这些工具函数会自动让前端存储(使用)与云端数据库保持同步;
-
这些工具函数已经对调用次数的资源消耗进行了优化,具体表现如下:
(1) 当你向数据库写入数据时,只需消耗1次调用次数,就完成了前端存储与云数据库的同步写入;如:
(2) 当你写入的数据实际上没有变化时(与数据库中一致),不会消耗调用次数;
(3) 当你从数据库中读取数据时,仅在第一次读取时消耗1次调用次数,后续读取数据库操作将不再消耗调用次数(即使读取的是不同的数据字段),因为会从前端缓存中读取;
(4) 即使用户明天或下周或几个月后重新打开了小程序,此时读取数据库依然不会消耗调用次数,因为会从前端中读取(上一篇文章说过,的存储时间非常长,几乎不会被删除);
(5) 通过搭配使用和函数,可以实现向数据库中写入多条(或多次)数据,但是仅消耗1次调用次数。而在节约资源的同时并不需要改变你的代码逻辑和编码习惯;
本文中所有保存用户配置数据的函数都会自动维护前端的存储与云数据库之间的自动同步,你并不需要关心实现细节,只需简单地调用即可。如果你还没有阅读上一篇文章,建议你先去阅读,因为上一篇文章中的内容是本篇文章的基础。
建议你在阅读本系列文章时,自己新建一个项目,然后跟着我的步骤在你的电脑上实践。因此,在本篇文章中,你需要先获取库中的代码。
你可以在github代码库:sdjl/WxMpCloudBooster下载,或者使用如下的命令:
然后使用类似这样的代码在你的项目中导入:
微信云开发允许同一个云环境共享给多个小程序使用,为了便于区分哪些表是属于哪个小程序的,我们约定使用小程序的英文名称作为表的前缀。
假设我们有两个小程序,项目的英文名称分别是和,那么所有小程序的表都以开头,小程序的表都以开头。
重构:假设前面的文章中创建的功能是属于小程序的,我们把表重命名为,把表重命名为。然后再修改页面的相关代码,把所有操作表的地方都改为操作表。
然后,为了保存小程序的用户数据,我们再分别新建和两个表,其中用于开发环境,用于生产环境。然后给这两个表均设置如下的访问权限:
修改权限步骤如图所示:
提醒:以结尾只是本系列文章的约定,不是必须的,但我建议你使用这种命名方式,以便于阅读后面的文章。
相关的所有函数都假设同一个用户在同一个表中最多只有一条记录,因此我们需要为和表用字段建立唯一索引(需删除默认的_openid索引),如图所示:
为了演示相关函数,我们新建一个设置页面,并让用户在页面中勾选“是否使用大字体”、“是否显示已完成的”两个设置。然后我们把这两个设置保存到数据库中。
请在下创建页面,如图所示:
然后把下面的代码复制到你的文件中:
然后按照下图添加编译模式:
重新编译后可看见如下页面:
注意看上面中的这几行关键代码:
这里我们实际上使用的是组件,但由于使用了微信内置的样式,所以外观上看起来像是组件。
当我们点击时,会触发函数。我们先把如下的代码复制到你的文件中:
在上面的js代码中,获得的是一个数组,表示有哪些被选中。然后我们使用函数判断和是否在数组中。当为时,表示用户勾选了“使用大字体”;当为时,表示用户勾选了“显示已完成todo”。
接下来,我们使用函数把用户的设置保存到数据库中。请把函数修改为如下代码:
这里添加是为了观察中的数据。
然后,点击按钮切换状态,用户配置就会自动写入表中。打开微信开发者工具的->,可以看到表中新增了一条记录,如图所示:
我们把这两个配置都保存到了属性下,表示它们是用于控制页面显示的。
然后,点击->,可以看到数据库中的数据同步保存到中了,如图所示:
注意:需要在中使用参数,才能在中看到数据,否则显示的是一串加密字符串。这里中的前缀是的缩写,是相关函数自动添加的。
Bug提醒:在微信开发者工具中查看时,发现有时候中的数据不会自动刷新。建议使用以下代码打印查看:
你可以尝试再次切换按钮的状态,你会发现中的数据总是和数据库中的数据保持一致。
当你每次点击按钮时,函数就会执行一次,然后会执行下面这两句代码:
那么上面这两句代码消耗了多少次“调用次数”呢?
答案是:1次。因为所有的相关函数都会根据前端中的数据判断是否需要写入数据库,当你点击第一个按钮时,第二行代码在执行时会发现的值并没有变化(被点击的不是它),因此不会访问数据库。
下一步,我们需要在用户进入设置页面时读取数据库中的设置,并初始化页面。请把函数修改为如下代码:
这样,重新进入设置页面时,按钮的初始状态就会和数据库保持一致。
那么这里设置了两个按钮的状态,消耗了多少次“调用次数”呢?
答案是:0次。因为所有的相关函数都会从前端中读取数据,并不需要访问数据库。
并且,存储是长期有效的,就算用户是几天后、几个月后再次打开小程序,读取数据时依然不会消耗调用次数。
那么,如果用户在微信APP中手动删除了小程序(此时前端存储会被删除),那么会发生什么情况呢?
当前端被删除后,首次调用任何相关函数时,会消耗1次调用次数,前端与数据库中的数据就自动完成同步了。
因此你不需要修改上面的任何代码,你不需要关心前端被删除的情况。如何保持数据同步,如何节约调用次数,都交给库来处理。
作业:由于在页面中根据设置切换字体大小等不是本文章的重点,就留给读者自己完成了。
除了用户配置相关的数据,其他任何数据都是可以使用相关函数来保存的。
例如你想要保存用户最近提交的文字,你可以使用如下代码:
或者保存到一个数组中:
由于相关函数内部使用了聚合查询,因此读取的单条数据可以达到5M(具体请参考文章三中“云数据库的限制”)。
但是,微信Storage文档中有如下规定:“单个 key 允许存储的最大数据长度为 1MB”,因此原则上不能存储超过1M的数据。
但是的但是,当我使用写入的数据明显超过1M时,没有报错,可以正常读写。因此,我认为微信文档中的1M限制是不准确的,实际上可以存储更大的数据。
但是的3次方,这并不保证所有设备都可以写入超过1M的前端数据,微信的政策可能会随时变化,建议自己测试一下。
如果需要保存的用户数据比较大,那么相关函数就不适用了。例如你为用户开发了一个云笔记应用,用户的笔记内容可能会很大。
我们先对上面的内容做一个小结:
-
在整个小程序的生命周期中,当你第一次调用相关函数时,库会自动处理前端与数据库之间的同步问题,并尽可能通过前端来减少调用次数。
-
你可以简单的认为所有相关函数在读取数据时是不消耗调用次数的。
-
数据缓存是长期有效的,哪怕用户几个月后再次打开小程序。
-
不只是用户配置,任何数据都可以使用相关函数来保存。
-
数据同步是跨页面的,只要访问的是同一个表(只有这一个条件)即可利用缓存。
-
单个用户的数据量在1M以下是安全的,超过1M时未知(5M以下应该没问题)。
-
每次最多只能写入512K数据,需要写入更大数据时,请分多次写入。
-
可用多个表保存不同的数据,会自动创建多个来保存对应表的数据。但前端所有的的总大小不能超过10M(微信限制)。
-
那些需要保存大量数据的场景,不适合使用相关函数。
-
当你不需要加密时,可使用参数。但对于同一张表,要么所有数据都加密,要么都不加密,否则可能会有解析异常。
-
当传给函数的参数等于时,可以删除该字段。
-
本篇文章介绍的所有函数都支持自动保持前端与数据库之间的同步。
添加到数组最后面
函数用于向数组配置中添加数据,例如你想要保存用户收藏的文章列表,可以使用如下代码:
如果字段不存在,函数会自动创建一个数组字段,并把添加到数组中。
此时使用函数读取字段,会得到如下结果:
再次调用函数,把添加到数组的后面:
添加到数组最前面
如果你想要把添加到数组的最前面,可以使用:
用限制数量
假设你只允许用户收藏3篇文章,那么可以使用参数:
看,原本在最前面的被删除了。当然,如果配合参数使用,会删除最后面的元素。
排除重复元素
如果收藏的文章列表出现了两篇相同的文章,就会显得很奇怪对吧?此时可以用避免数组中出现重复元素:
函数发现已经在数组中了,由于不允许重复,所以只是把移动到了数组的最后面。
当然,如果配合使用,会把移动到数组的最前面。
push对象
但是,如果我们保存的是文章的id,用户在打开收藏页时,还需要使用id去读取文章数据,这样很麻烦。
此时,可以直接把文章对象保存到数组中,例如:
对象排重
当把对象添加到数组中时,若参数则会根据来排重,例如:
函数发现已经在数组中了,由于不允许重复,先是移除了旧的文章对象,然后把新的文章对象添加到了数组的最后面。
这在用户收藏重复的文章时特别有用,并且会自动保持最新的文章(这里指增加了属性的文章)在最后面。
使用时注意以下几点:
- 函数添加对象时,总是根据来判断对象是否重复。
- 如果你push的对象没有字段,那么就视为所有对象都是"重复的”,此时建议。
- 如果数组中有对象、字符串、数字等多种类型的元素,请保持。
- 注意是,不是
不用担心“指针”问题
如果把对象添加到数组中,然后修改了对象的属性,会怎样?
两次push的是同一个对象,那么第一次push进去的对象的会变成“标题2”吗?
答案是不会,不用担心这个问题,输出的结果是:
从最后面删除匹配元素
假设你使用存储对象的方式保存了用户收藏的文章列表,当用户点击“取消收藏”按钮时,可以使用函数来删除数组中的元素。
这里只需要传入对象的即可,而不需要传入整个文章对象。表示“挑选并拔出”的意思。
如果你需要的不是“_id相同就删除”,而是整个对象文档必须完全相同才删除,可以设置参数。
从最前面删除匹配元素
如果你想要从数组的最前面删除匹配元素,可以使用:
删除多个元素
默认情况下函数只删除第一个匹配元素,如果你想要删除多个匹配元素,可以使用参数:
上面的代码会从数组的末尾向前查找,最多删除5个匹配元素。表示实际删除的元素个数。
从最后面pull一个元素
函数用于从数组的最后面取出数据,假设用户有一个“等待阅读的文章列表”,现在你想要把最后一篇文章取出来给用户阅读,可以使用如下代码:
函数返回结果是最后一个元素,同时从数组中删除了这个元素。
pull多个元素
默认只取出一个元素,如果你想要取出多个元素,可以使用参数:
注意以下几点:
-
当时,返回的是数组的一个元素,而不是一个数组(除非这个元素本身也是一个数组)。
-
当的时候,返回的是一个数组。并且这个数组的顺序是从后往前取的。
-
当时,若没有找到元素,会返回。当时,若没有找到任何匹配元素,会返回空数组。
从最前面pull元素
想要从数组的最前面取出数据,可以使用:
而从前面取出的元素顺序与在数组中的顺序一致。
这3个操作数组的函数几乎每次都会消耗1次调用次数,但以下几种情况不会消耗调用次数:
- 在不允许重复时,反复向最后面(或最前面)添加相同的元素时;
- 没有找到任何匹配元素,返回时。
- 从空数组中pull元素,返回或空数组时;
一次只能设置一个字段的值,而反复调用会消耗大量调用次数。
允许你仅消耗1次调用次数,就可以一次性写入多个字段的值。
前面设置和的代码可以改成如下形式:
你可以向中添加任意多个字段,会忽略与前端中的值相同的字段,然后把那些实际上发生了变化的字段传递给数据库进行写入操作。
过滤掉未发生变化的字段,一是为了更快的执行速度,二是微信限制写入的数据不能超过512K,尽可能减少写入的数据量。
注意,如果把上面的代码写成下面的形式:
这样写也可以正确的设置和的值,但是和前面的代码有区别。
前面的代码是在的基础上设置和,如果下还有其他配置,其他配置会被保留。
而后面的代码是直接把替换了,的其他配置会被删除。
还记得前面初始化页面时,我们用读取了对象吗。
但是只能读取单个配置的值,如果你想要读取多个配置的值,可以使用函数:
传给的第二个参数是一个对象,对象的是字段名,是此配置不存在时的默认值。
-
在有至少1个字段发生变化时,消耗1次调用次数;否则不消耗调用次数。
-
会从前端中读取数据,不消耗调用次数。
如果你的配置页面有很多可以设置的选项,用户每次点击按钮都会写数据库,万一用户点着玩呢?
此时可以使用函数,它会把需要修改的配置先放入缓冲区,然后可在退出页面时一次性写入数据库。
向缓冲区中添加数据:
注意:以上代码不需要和。
然后在事件(用户退出当前页面)中调用函数:
提醒:记得本文使用只是为了方便观察中的数据,你在实际开发时可以不加这个参数。
把所有在缓冲区的数据一次性写入数据库。与相同,只有发生变化的字段才会被写入数据库。
注意:这里一定要添加,等待函数执行完毕才能退出页面。否则微信APP会认为这个页面已经退出了,异步代码可能无法保证会被执行。
你也可以给用户一个“保存”按钮,点击“保存”时才调用函数。若用户没有保存直接返回上一页的话,则取消所有的修改。此时可以用函数清空缓冲区。
如果要清空所有表的缓冲区,可以不传递参数:
对了,调用后也会自动清空对应表的缓冲区。
-
与不消耗调用次数。
-
在有至少1个字段发生变化时,消耗1次调用次数;否则不消耗调用次数。
-
本篇文章介绍了相关的函数,这些函数可以帮助你更方便的保存用户的配置数据,而且还可以自动保持前端与数据库之间的同步。
-
利用缓存,可以瞬间读取数据,还可以大幅降低调用次数。
-
不仅仅是“配置”数据,用户的任何数据都可以使用相关函数来保存。
-
对于较大的用户数据(超过5M),建议单独使用一个表来保存,并使用上一篇文章中的和函数减少调用次数。
-
若因某些原因导致前端与数据库中的数据不一致,可使用以下方法删除前端中的数据(然后重新调用相关函数会自动重新同步):
(1) 在“微信开发者工具”中,可在“调试器”的“Storage tab”中手动删除。
(2) 在手机上,可以拖动小程序到“垃圾桶”中删除,然后重新打开小程序。
(3) 或用删除指定表的数据。