微信小程序云开发之云数据库入门

微信小程序云开发之云数据库入门

介绍

开发者可以使用云开发开发微信小程序、小游戏,无需搭建服务器,即可使用云端能力。
其基础能力数据库,是一个JSON数据库,作用是无需自建数据库,就可以在微信小程序前端操作数据库,也能在云函数中读写数据库。

前置条件

  • 在新建项目是一定要勾选开启云服务
  • 在微信开发者工具中点击云开发构建集合。


    image

注意事项

数据库 API 分为小程序端和服务端两部分,小程序端 API 拥有严格的调用权限控制,开发者可在小程序内直接调用 API 进行非敏感数据的操作。对于有更高安全要求的数据,可在云函数内通过服务端 API 进行操作。云函数的环境是与客户端完全隔离的,在云函数上可以私密且安全的操作数据库。

简言之:读写数据权限方面,微信小程序最低,云函数和云数据库一样高。

如果我们需要给予小程序相应权限,也是有办法的。我们可以在云开发控制台中设置微信小程序读取权限来达到自身项目的需求。

image

实例

该实例包含数据库开发全过程,涉及链接 获取集合 增删改查 检索,新建好名称为user的集合就能运行,供大家借鉴参考。(增删改查权限如果云开发控制台没有设置,有可能报错,设置一下即可)

废话不说,源码献上

demo.wxml


<!--index.wxml-->
<view class="container">
  <!-- 用户 openid -->
  <view class="userinfo">
    <button open-type="getUserInfo" bindgetuserinfo="onGetUserInfo" class="userinfo-avatar" style="background-image: url({{avatarUrl}})" size="default"></button>
    <view class="userinfo-nickname-wrapper">
      <button class="userinfo-nickname" bindtap="onGetOpenid">点击获取 openid</button>
    </view>
  </view>
  <!-- 增加数据 -->
  <view class="uploader">
    <view bindtap="addData" class="uploader-text">
      <text>增加数据</text>
    </view>
    <view class="page-body">
      <form catchsubmit="formSubmit" catchreset="formReset" hidden="{{isFormHidden}}">
        <!-- 开关
          <view class="page-section page-section-gap">
            <view class="page-section-title">switch</view>
            <switch name="switch" />
          </view> -->
        <!-- <view class="section">
          <view class="section__title">性别</view>
          <picker bindchange="bindPickerChange" value="{{index}}" range="{{array}}">
            <view class="picker">
              性别: {{array[index]}}
            </view>
          </picker>
        </view> -->
        <!-- 单选
          <view class="page-section page-section-gap">
            <view class="page-section-title">radio</view>
            <radio-group name="radio">
              <label>
                <radio value="radio1" />选项一</label>
              <label>
                <radio value="radio2" />选项二</label>
            </radio-group>
          </view> -->
        <!-- 多选
          <view class="page-section page-section-gap">
            <view class="page-section-title">checkbox</view>
            <checkbox-group name="checkbox">
              <label>
                <checkbox value="checkbox1" />选项一</label>
              <label>
                <checkbox value="checkbox2" />选项二</label>
            </checkbox-group>
          </view> -->
        <!-- 滑动选择
          <view class="page-section page-section-gap">
            <view class="page-section-title">slider</view>
            <slider value="50" name="slider" show-value></slider>
          </view> -->
        <!-- 输入框 -->
        <view class="page-section">
          <view class="page-section-title">
            <input class="weui-input" name="userName" placeholder="请输入用户名称" />
          </view>
        </view>
        <!-- 输入框 -->
        <view class="page-section">
          <view class="page-section-title">
            <input class="weui-input" name="itCard" placeholder="请输入昵称" />
          </view>
        </view>
        <!-- 输入框 -->
        <view class="page-section">
          <view class="page-section-title">
            <input class="weui-input" name="phone" placeholder="请输入电话" />
          </view>
        </view>
        <!-- 输入框 -->
        <view class="page-section">
          <view class="page-section-title">
            <input class="weui-input" name="email" placeholder="请输入邮箱" />
          </view>
        </view>
        <!-- 提交 -->
        <view class="btn-area">
          <button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">提交</button>
          <button style="margin: 30rpx 0" type="primary" formType="submit">Submit</button>
          <button style="margin: 30rpx 0" formType="reset">Reset</button>
        </view>
      </form>
    </view>
  </view>
  <!-- 查看数据 -->
  <view class="uploader">
    <view bindtap="seeData" class="uploader-text">
      <text>查看数据</text>
    </view>
    <view class="uploader-text" wx:for="{{user}}" wx:key="key">
      <text>{{item.userName}}</text>
    </view>
  </view>
  <!-- 修改数据 -->
  <view class="uploader">
    <view bindtap="updata" class="uploader-text">
      <text>修改数据</text>
    </view>
    <view class="page-body">
      <form catchsubmit="updatasubmit" catchreset="updatareset" hidden="{{isupdataform}}">
        <view class="btn-area">
          <input name="userName" placeholder="重新输入姓名"></input>
        </view>
        <view class="btn-area">
          <button style="margin:30rpx 0" type="primary" formType="submit">更新</button>
          <button style="margin:30rpx 0" type="warn" formType="reset">重置</button>
        </view>
      </form>
    </view>
  </view>
  <!-- 删除数据 -->
  <view class="uploader">
    <view bindtap="deleteData" class="uploader-text">
      <text>删除最近一条数据</text>
    </view>
    <view class="uploader-text" wx:for="{{users}}" wx:key="key">
      <text>{{item.userName}}</text>
    </view>
  </view>
  
</view>

demo.js


//index.js
const app = getApp()

//获取数据库环境引用
const db = wx.cloud.database({
  env: "输入自己的数据库环境,也可不输入,不输入默认查找当前环境"
})

//链接数据库中的集合
const pave = db.collection("PavmentRecord")
const user = db.collection("user")

// util.js
//格式化日期,输出格式为y-m-d h m s
const formatTime = date => {
  const year = date.getFullYear()
  const month = date.getMonth() + 1
  const day = date.getDate()
  const hour = date.getHours()
  const minute = date.getMinutes()
  const second = date.getSeconds()
  return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute].map(formatNumber).join(':')   //返回年月日,时分秒
}

//转换int类型为string
const formatNumber = n => {
  n = n.toString()
  return n[1] ? n : '0' + n
}


Page({
  data: {
    avatarUrl: '../../images/user-unlogin.png',
    userInfo: {},
    logged: false,
    takeSession: false,
    requestResult: '',
    isFormHidden: true,
    isupdataform: true,
    users: {},
    array: ['男', '女'],
    cloud: ''
  },
  onShareAppMessage() {
    return {
      title: 'picker-view',
      path: 'page/component/pages/picker-view/picker-view'
    }
  },
  onLoad: function () {
    if (!wx.cloud) {
      wx.redirectTo({
        url: '../chooseLib/chooseLib',
      })
      return
    }
    var that = this
    // 获取用户信息
    wx.getSetting({
      success: res => {
        if (res.authSetting['scope.userInfo']) {
          // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
          wx.getUserInfo({
            success: res => {
              that.setData({
                avatarUrl: res.userInfo.avatarUrl,
                userInfo: res.userInfo
              })
            }
          })
        }
      }
    })
  },
  bindPickerChange: function (e) {
    console.log('picker发送选择改变,携带值为', e.detail.value)
    this.setData({
      index: e.detail.value
    })
  },
  onGetUserInfo: function (e) {
    if (!this.data.logged && e.detail.userInfo) {
      this.setData({
        logged: true,
        avatarUrl: e.detail.userInfo.avatarUrl,
        userInfo: e.detail.userInfo
      })
    }
  },
  onGetOpenid: function () {
    // 调用云函数
    wx.cloud.callFunction({
      name: 'login',
      data: {},
      success: res => {
        console.log('[云函数] [login] user openid: ', res.result.openid)
        app.globalData.openid = res.result.openid
        wx.navigateTo({
          url: '../userConsole/userConsole',
        })
      },
      fail: err => {
        console.error('[云函数] [login] 调用失败', err)
        wx.navigateTo({
          url: '../deployFunctions/deployFunctions',
        })
      }
    })
  },
  //增加数据
  addData: function () {
    this.setData({
      isFormHidden: false
    })
  },
  getPhoneNumber: function (e) {
    console.log(e)
  },
  //提交表单
  formSubmit(e) {
    const ur = e.detail.value;
    console.log("提交表单信息如下:")
    console.lot(ur)
    var date = formatTime(new Date());
    console.log(date)
    pave.add({
      data: {
        userName: 'test',
        userPhone: '15239942334',
        diseaseName: "test",
        symCom: "test",
        recordTime: date,
        payMoney: 100.0
      },
    }).then(res => {
      console.log(res)
    }).catch(function (e) {
      console.log(e)
    })
  },
  //重置表单
  formReset(e) {
    console.log('form发生了reset事件,携带数据为:', e.detail.value)
    this.setData({
      chosen: ''
    })
  },
  //查看数据
  seeData(e) {
    user.get().then(
      res => {
        console.log(res.data)
        this.setData({
          user: res.data
        })
      }
    )
  },
  //修改数据
  updata(e) {
    this.setData({
      isupdataform: false
    })
  },
  updatasubmit(e) {
  //查找user集合中id为以下数据的值,可以在e中获取,这里我简单写了一个。
    user.where({
      "_id": 'dc277a235f081fc20009534043d370cc'
    }).set({
      data: {
        "userName": e.data.userName
      },
      success: function (res) {
        console.log("更新成功:" + res)
      }
    })
  },
  updatareset(e) {
    this.setData({
      chosen: ''
    })
  },
  deleteData(e) {
    var that
    wx.cloud.callFunction({
      name: 'deleteData',
      data: {
        object: 'user',
        id: 'a7d38b365f0852c2000c0a3b0b7aae7a'
      }
    }).then(res => {
      console.log(res)
      that = res.data
    })

  }
})


demo.wxss


/**index.wxss**/
page {
  background: #f6f6f6;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}
.userinfo, .uploader, .tunnel {
  margin-top: 40rpx;
  height: 140rpx;
  width: 100%;
  background: #fff;
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-left: none;
  border-right: none;
  display: flex;
  flex-direction: row;
  align-items: center;
  transition: all 300ms ease;
}
.userinfo {
  padding-left: 120rpx;
}
.userinfo-avatar {
  width: 100rpx;
  height: 100rpx;
  margin: 20rpx;
  border-radius: 50%;
  background-size: cover;
  background-color: white;
}
.userinfo-avatar[size] {
  width: 100rpx;
}
.userinfo-avatar:after {
  border: none;
}
.userinfo-nickname {
  font-size: 32rpx;
  color: #007aff;
  background-color: white;
  background-size: cover;
  text-align: left;
  padding-left: 0;
  margin-left: 10px;
}
.userinfo-nickname::after {
  border: none;
}
.userinfo-nickname-wrapper {
  flex: 1;
}
.uploader, .tunnel {
  height: auto;
  padding: 0 0 0 40rpx;
  flex-direction: column;
  align-items: flex-start;
  box-sizing: border-box;
}
.uploader-text, .tunnel-text {
  width: 100%;
  line-height: 52px;
  font-size: 34rpx;
  color: #007aff;
}
.uploader-container {
  width: 100%;
  height: 400rpx;
  padding: 20rpx 20rpx 20rpx 0;
  display: flex;
  align-content: center;
  justify-content: center;
  box-sizing: border-box;
  border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.uploader-image {
  width: 100%;
  height: 360rpx;
}
.tunnel {
  padding: 0 0 0 40rpx;
}
.tunnel-text {
  position: relative;
  color: #222;
  display: flex;
  flex-direction: row;
  align-content: center;
  justify-content: space-between;
  box-sizing: border-box;
  border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.tunnel-text:first-child {
  border-top: none;
}
.tunnel-switch {
  position: absolute;
  right: 20rpx;
  top: -2rpx;
}
.disable {
  color: #888;
}
.service {
  position: fixed;
  right: 40rpx;
  bottom: 40rpx;
  width: 140rpx;
  height: 140rpx;
  border-radius: 50%;
  background: linear-gradient(#007aff, #0063ce);
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3);
  display: flex;
  align-content: center;
  justify-content: center;
  transition: all 300ms ease;
}
.service-button {
  position: absolute;
  top: 40rpx;
}
.service:active {
  box-shadow: none;
}
.request-text {
  padding: 20rpx 0;
  font-size: 24rpx;
  line-height: 36rpx;
  word-break: break-all;
}


demo.json


{
  "usingComponents": {},
  "navigationBarTitleText":"数据操作"
}


更多微信小程序相关查看我的程序员提升专栏,有需要请评论区留言。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351