-

云开发数据库支持实时推送变更数据的能力,给定查询条件,每当数据库更新而导致查询条件对应的查询结果发生变更时,在小程序端就可收到一个更新事件,通过更新时间返回的对象就可获取更新内容和更新后的查询结果快照。

一、应用场景与注意事项

1、实时数据推送的应用场景

当用户在小程序端停留时间比较长,需要关注其他用户的行为而导致的一些数据的实时变化时,就可以使用实时数据推送,只要数据发生变动,都能实时的在前端呈现出来。实时数据推送有着广泛的应用场景:

  • 聊天/即时通信:小游戏内聊天、大厅广播、区服广播等;企业内部小程序中的即时通信能力等;

  • 直播实时弹幕:在开视频直播时,用户点赞量、发送的礼物、评论等都可以实时在直播间滚动播放;

  • 多人小游戏:使用状态同步的小游戏,如棋牌类等回合制游戏等

  • 协作工具:如在线协作文档、团队任务管理等,用户的编辑信息会实时同步到参与方;

  • 实时应用状态同步:可以实时获取最新文章、以及最新评论、点赞、通知等内容,让交互更顺畅自然;比如看体育直播,和网友实时互动;

  • 在线商城:比如抢购时的库存量在不刷新界面的情况下实时更新;价格会实时变化的拼购;

  • 股票基金报价:股票的价格总是瞬息万变的,当你打开小程序查看股票价格时,你希望是实时的,而不是当你刷新页面时,数据才会同步;

  • 基于位置的应用,比如你和你的好友开启了位置共享;或者你在景区内不断移动,景区会实时根据你的位置推送相关的景区介绍;

2、实时数据推送注意事项

1、实时数据推送只支持小程序端(Web端)

实时数据推送的watch请求只支持在小程序端(Web端)等前端调用,不支持云函数端。

2、不要滥用实时数据推送

只有在小程序端需要快速同步数据变动响应时,才需要使用实时数据推送,一般情况用页面刷新即可;也只有在用户在页面停留时间比较长的情况下才可以使用实时数据推送,

3、注意集合的权限设置

集合的权限需要设置为所有人可读,仅创建者可读写。集合的读权限设置在实时数据推送里同样生效,如果权限是设置为仅可读用户自己的数据,则监听的时候无法监听到非用户自己创建的数据。

4、查询不支持field

监听集合中符合查询条件的数据的更新事件。使用 watch 时,支持 where, orderBy, limit,不支持 field。在监听中,orderBy 最多可以指定 5 个排序字段,limit 最大值为 200。limit 默认不存在即取所有数据。

5、只监听必要的数据

监听时应明确查询条件,只监听必须用到的数据,避免监听不必要的数据,以此提高初次加载数据的性能以及接收数据变更的性能。

6、监听返回的数据不受默认 20 条限制

监听返回的数据可能超过 20 条,不受小程序端默认 20 条上限限制。一次监听的记录数上限为 5000,若超出上限会抛错并停止监听。监听过大量的数据时初始化会较慢,对监听效率也有影响,如果预期监听发起时少于 5000,但后续有可能超过 5000,请注意在即将超过时重新监听并保证不超过 5000。

二、实时数据推送案例

数据库的实时监听既可以监听集合中符合查询条件的文档的变化,也可以监听单个doc,下面以监听单个doc为例。使用开发者工具新建一个页面,比如snapshot,然后在snapshot.wxml里输入一个可以修改数据的button,比如点击一下就会增加点赞次数:

<button bindtap="addStar">点赞{{stars}}</button>

然后在数据库里新建一个集合比如livevideo(注意要修改集合的权限可以用安全规则修改为所有人可读可写,或者将点赞采用调用云函数的方式),添加一个简单的记录比如:

"_id":"room2020032101",
"star":0

再在snapshot.js的data属性里声明stars,以及添加事件处理函数addStar,还有就是在页面的onLoad生命周期函数里监听数据的变化,并将数据的变化渲染到页面。

  data:{
    stars:0
  },
  onLoad: function() {
    const that =this
    const watcher = db.collection('livevideo').doc('room2020032101')
    .watch({
      onChange: function(snapshot) {
        that.setData({
          stars:snapshot.docs[0].star
        })
        console.log('文档数据发生变化', snapshot)
      },
      onError: function(err) {
        console.error('监听因错误停止', err)
      }
    })
  }
  addStar(){
    db.collection('livevideo').doc('room2020032101').update({
      data: {
        star:  _.inc(1)
      },
      success: console.log,
      fail: console.error
    })
  }

watch有两个属性,onError是失败回调,onChange是成功回调,成功回调传入的参数 snapshot 是变更快照。onChange 和 onError 是必传参数。onChange 用于接收变更快照,onError 用于处理监听错误。如果监听发起失败或监听过程中出现不可恢复的错误,则会终止监听并通过 onError 抛出异常。onChange 会在第一次监听初始化及后续数据变更时收到推送事件。第一次初始化时会收到的查询条件对应的查询结果,后续变更事件会包含变更内容和变更后的查询结果快照。

>如果想要预览实时数据推送的效果,可以使用开发者工具的多账号调试,在开发者工具栏-工具-多账号调试即可。当A用户点击点赞的button,点赞的数量就会实时同步给所有在线用户的小程序端。在多账号的控制台里也能实时看到打印的信息。

我们可以留意打印的snapshot对象,这个对象包含的信息非常多,主要有

  • type:快照类型,仅在第一次初始化数据时有值为 init,也就是当我们加载snapshot页面,在有用户点击button之前,type为init,一旦数据变化,type为undefined;

  • id为变更事件id,记录了事件变更的次数;

  • docChanges:表示更新事件数组,前端操作

  • docs:数据快照,表示此更新事件发生后查询语句对应的查询结果

docChanges对象里的queueType和dataType字段,前者表示更新事件对监听列表的影响,后者表示记录的具体更新类型。注意这两者的不同,比如上面的案例我们只是更新了字段的值,所以它为update;如果监听的记录出现增加,或者减少,queueType的值就会有所不同,而removedFields也会有删除的字段;而dataType字段的值则与数据库请求的方法相对应,而所有更新的字段及字段更新后的值都会在updatedFields对象里。