《小程序02:云开发之增删改查》

一、前置操作

javascript 复制代码
// 一定要用``这个符号包含里面的${}才会生效
wx.showToast({
  title: `获取数据成功:${colorLista}`,
})

1.1:初始化介绍

**1、获取数据库引用:**在开始使用数据库 API 进行增删改查操作之前,需要先获取数据库的引用

javascript 复制代码
const db = wx.cloud.database()

2、绑定对象参数 :如需获取其他环境的数据库引用,可以在调用时传入一个对象参数,在其中通过 env 字段指定要使用的环境

例:假设有一个环境名为qxjs-xxxxxtest,用做测试环境,那么可以如下获取测试环境数据库:

javascript 复制代码
const testDB = wx.cloud.database({
  env: 'qxjs-xxxxxtest'
})

3、获取数据库下的集合:要操作一个集合,需先获取它的引用。在获取了数据库的引用后,就可以通过数据库引用上的 collection 方法获取一个集合

javascript 复制代码
const todos = db.collection('user')

4、获取指定ID的记录:获取集合的引用并不会发起网络请求去拉取它的数据,我们可以通过此引用在该集合上进行增删查改的操作,除此之外,还可以通过集合上的 doc 方法来获取集合中一个指定 ID 的记录的引用

javascript 复制代码
const todo = db.collection('user').doc('todo-identifiant-aleatoire')

1.2:数据库-集合创建

1、创建一个集合并添加数据
(1)简单的集合:定义一个user集合,以及它的字段(可以手动添加记录、也可以下载下面user.json文件导入进去)
user.json
(2)复杂集合:支持多种数据类型list、boolean、string(或者是导入文件,json文件和代码区域有不同)

002_语雀云开发tools使用的数据.json

2、获取集合数据库里的数据前,需要开放集合的查询权限

3、绑定env数据库ID

4、模拟一个场景:点击一个按钮,调用getData方法,然后查询数据库里面的数据

那么可以先搭建好下面这个简单的框架,以下代码主要是诠释click方法在哪里定义,在哪里设置(wxml和js文件中)

javascript 复制代码
//----------------------index.wxml文件

<!-- 内容部分 -->
<view class="test_content">
  <button class="qxjs-btn def bg-green round" bindtap="getData">查询所有</button> 
</view>


//----------------------index.js文件
const db = wx.cloud.database()//连接数据库
Component({

  //1:组件的属性列表
  properties: {

  },

  //2:组件的初始数据 
  data: {
    testData: "12346",
  },

  //3:组件的方法列表
  methods: {
 	//这是bindtap方法getData
  }
})

二、查询数据

2.1:获取集合数据-get

1、如果要获取一个集合的数据,比如获取 user 集合上的所有记录,可以在集合上调用 get 方法获取,但通常不建议这么使用,在小程序中我们需要尽量避免一次性获取过量的数据,只应获取必要的数据。为了防止误操作以及保护小程序体验,小程序端在获取集合数据时服务器一次默认并且最多返回 20 条记录,云函数端这个数字则是 100。开发者可以通过 limit 方法指定需要获取的记录数量,但小程序端不能超过 20 条,云函数端不能超过 100 条

javascript 复制代码
// 方法1
db.collection('user').get({
  success: function(res) {
    // res.data 是一个包含集合中有权限访问的所有记录的数据,不超过 20 条
    console.log(res.data)
  }
})


//方法2:使用Promise风格
db.collection('user').get().then(res => {
  // res.data 是一个包含集合中有权限访问的所有记录的数据,不超过 20 条
  console.log(res.data)
})

2、下面是在云函数端获取一个集合所有记录的例子,因为有最多一次取 100 条的限制,因此很可能一个请求无法取出所有数据,需要分批次取:

javascript 复制代码
// reduce函数查重:遍历所有元素,判断该元素是否已经存在于累加变量中
// reduce函数的回调函数有四个参数:累加器(acc),当前值(cur),当前索引(index)和数组本身(self)
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
const MAX_LIMIT = 100
exports.main = async (event, context) => {
  // 先取出集合记录总数
  const countResult = await db.collection('todos').count()
  const total = countResult.total
  // 计算需分几次取
  const batchTimes = Math.ceil(total / 100)
  // 承载所有读操作的 promise 的数组
  const tasks = []
  for (let i = 0; i < batchTimes; i++) {
    const promise = db.collection('todos').skip(i * MAX_LIMIT).limit(MAX_LIMIT).get()
    tasks.push(promise)
  }
  // 等待所有
  return (await Promise.all(tasks)).reduce((acc, cur) => {
    return {
      data: acc.data.concat(cur.data),
      errMsg: acc.errMsg,
    }
  })
}

2.2:条件查询-where

1、我们也可以一次性获取多条记录。通过调用集合上的 where 方法可以指定查询条件,再调用 get 方法即可只返回满足指定查询条件的记录,比如获取用户的所有未完成的待办事项:
查询方法一:

(1)查询出 user 集合中 【_openid 等于 user-open-id 且 done 等于 false 且 ...】 的记录

(2)查找条件中匹配一个嵌套字段:获取颜色标识为黄色

javascript 复制代码
db.collection('user').where({
  _openid: 'user-open-id',
  done: false,
  style: {
    color: 'yellow'
  }
})
.get({
  success: function(res) {
    // res.data 是包含以上定义的两条记录的数组
    console.log(res.data)
  }
})

查询方法二:

用 "点表示法" 表示嵌套字段:

javascript 复制代码
db.collection('todos').where({
  _openid: 'user-open-id',
  'style.color': 'yellow'
})
.get({
  success: function(res) {
    console.log(res.data)
  }
})

2.3:获取1条数据-doc

我们先来看看如何获取一个记录的数据,通过调用 get 方法获取数据:获取ID 为 todo-identifiant-aleatoire 的在集合 user 上的记录

注意:doc里面的内容是"_id"
方法一:

javascript 复制代码
db.collection('user').doc('todo-identifiant-aleatoire').get({
  success: function(res) {
    // res.data 包含该记录的数据
    console.log(res.data)
  }
})

方法二: Promise 风格调用

javascript 复制代码
db.collection('todos').doc('todo-identifiant-aleatoire').get().then(res => {
  // res.data 包含该记录的数据
  console.log(res.data)
})

三、插入数据

3.1:插入一条数据-doc

可以通过在集合对象上调用 add 方法往集合中插入一条记录。还是用待办事项清单的例子,比如我们想新增一个待办事项:

**

javascript 复制代码
db.collection('user').add({
  // data 字段表示需新增的 JSON 数据
  data: {
    // _id: 'todo-identifiant-aleatoire', // 可选自定义 _id,在此处场景下用数据库自动分配的就可以了
    description: "learn cloud database",
    due: new Date("2018-09-01"),
    tags: [
      "cloud",
      "database"
    ],
    // 为待办事项添加一个地理位置(113°E,23°N)
    location: new db.Geo.Point(113, 23),
    done: false
  },
  success: function (res) {
    // res 是一个对象,其中有 _id 字段标记刚创建的记录的 id
    console.log("成功:"+res)
  },
  fail:function(res){
    console.log("失败"+res)
  },
  complete:function(res){
    console.log("complete"+res)
  }
})

操作方法二:Promise风格

只要传入对象中没有 success, fail 或 complete,那么 add 方法就会返回一个 Promise

javascript 复制代码
db.collection('user').add({
  // data 字段表示需新增的 JSON 数据
  data: {
    description: "learn cloud database",
    due: new Date("2018-09-01"),
    tags: [
      "cloud",
      "database"
    ],
    location: new db.Geo.Point(113, 23),
    done: false
  }
})
.then(res => {
  console.log(res)
})

四、更新数据

1、更新数据主要有两个方法:

(1)API名称为:update(局部更新一个或多个记录)

(2)API名称为:set(替换更新一条记录)

2、更新指令-用于复杂操作:使用格式"_.指令(xxx)"

(1)set:设置字段为指定值

(2)remove:删除字段

(3)inc:原子自增字段值

(4)mul:原子自乘字段值
数据类型操作

(5)push:如字段值为数组,往数组尾部增加指定值

(6)pop :如字段值为数组,从数组尾部删除一个元素

(7)shift:如字段值为数组,从数组头部删除一个元素

(8)unshift:如字段值为数组,往数组头部增加指定值
3、定义const _ = db.command表示需要使用查询、更新指令

4.1:局部更新-update一条数据

使用update方法可以局部更新一个记录或者一个集合中的记录,局部更新意味着只有指定的字段会受到更新,其它字段不受影响。

注意:doc里面的内容是"_id"

案例1(直接更新):一条数据是"todo-identifiant-aleatoire"的记录,更新它的done属性为false

javascript 复制代码
db.collection('user').doc('todo-identifiant-aleatoire').update({
  // data 传入需要局部更新的数据
  data: {
    // 表示将 done 字段置为 true
    done: true
  },
  success: function (res) {
    // res 是一个对象,其中有 _id 字段标记刚创建的记录的 id
    console.log("成功:"+res.data)
  },
  fail:function(res){
    console.log("失败"+res)
  },
  complete:function(res){
    console.log("complete"+res)
  }
})

案例2(使用指令inc):一条数据是"todo-identifiant-aleatoire"的记录,在原有progress字段的基础上加上10

javascript 复制代码
const _ = db.command
db.collection('user').doc('todo-identifiant-aleatoire').update({
  data: {
    // 表示指示数据库将字段自增 10
    progress: _.inc(10)
  },
  success: function(res) {
    console.log(res.data)
  }
})

案例3(使用指令push):一条数据是"todo-identifiant-aleatoire"的记录,在数据组tags里面多一个标签

字段是个数组,那么我们可以使用 push、pop、shift 和 unshift 对数组进行原子更新操作

javascript 复制代码
const _ = db.command
db.collection('user').doc('todo-identifiant-aleatoire').update({
  data: {
    tags: _.push('mini-program')
  },
  success: function(res) {
    console.log(res.data)
  }
})

案例4(使用指令set):

(1)更新 style.color 字段为 'blue' 而不是把 style 字段更新为 { color: 'blue' } 对象

javascript 复制代码
const _ = db.command
db.collection('user').doc('todo-identifiant-aleatoire').update({
  data: {
    style: {
      color: 'blue'
    }
  },
  success: function(res) {
    console.log(res.data)
  }
})

(2)使用set将这个 style 字段更新为另一个{ color: 'blue' }对象

javascript 复制代码
onst _ = db.command
db.collection('user').doc('todo-identifiant-aleatoire').update({
  data: {
    style: _.set({
      color: 'blue'
    })
  },
  success: function(res) {
    console.log(res.data)
  }
})

**4.2:局部更新-update多条数据** 如果需要更新多个数据,需在 Server 端进行操作(云函数),在 where 语句后同样的调用 update 方法

案例1:比如将所有未完待办事项的进度加 10%: ```javascript // 使用了 async await 语法 const cloud = require('wx-server-sdk') const db = cloud.database() const _ = db.command

exports.main = async (event, context) => {

try {

return await db.collection('user').where({

done: false

})

.update({

data: {

progress: _.inc(10)

},

})

} catch(e) {

console.error(e)

}

}

<a name="Ya4zw"></a>
### **4.3:替换更新-set更新一条数据**
1、如果需要替换更新一条记录,可以在记录上使用 set 方法,替换更新意味着用传入的对象替换指定的记录(**相当于将之前那条记录替换成新的这个条记录中**)<br />2、如果指定 ID 的记录不存在,则会自动创建该记录,该记录将拥有指定的 ID。<br />案例1:去掉style中一个属性,更改due和location
```javascript
const _ = db.command
db.collection('user').doc('todo-identifiant-aleatoire').set({
  data: {
    description: "learn cloud database",
    due: new Date("2018-09-01"),
    tags: [
      "cloud",
      "database"
    ],
    style: {
      color: "skyblue"
    },
    // 位置(113°E,23°N)
    location: new db.Geo.Point(113, 23),
    done: false
  },
  success: function(res) {
    console.log(res.data)
  }
})

五、删除数据

5.1:删除一条记录-doc

案例1:对记录使用 remove 方法可以删除该条记录

javascript 复制代码
db.collection('user').doc('todo-identifiant-aleatoire').remove({
  success: function(res) {
    console.log(res.data)
  }
}) 

案例2:通过index.wxml和index.js案例举例子,诠释如何实现表单的方式删除数据(此案例借鉴csdn用户:蓝黑2020

注意:前面的 btnSubmit() 函数,最后面要加一个逗号分隔一下。

html 复制代码
//---------------index.wxml
<form bindsubmit="btnDelete">
  ID:<input name="id" placeholder="请输入要删除的ID"/>
  <button type="primary" form-type="submit">删除</button>
  <button type="primary" form-type="reset">重置</button>
</form>
javascript 复制代码
//---------------index.js
btnDelete(res) {
var id = res.detail.value.id

db.collection("table0508").doc(id).remove().then(res => {
    console.log(res)
    wx.showToast({
      title: '删除成功!',
    })
  })
},

5.2:删除多条记录-where和remove

如果需要更新多个数据,需在 Server 端进行操作(云函数) 。可通过 where 语句选取多条记录执行删除,只有有权限删除的记录会被删除。

案例1:比如删除done属性为true的数据

javascript 复制代码
// 使用了 async await 语法
const cloud = require('wx-server-sdk')
const db = cloud.database()
const _ = db.command

exports.main = async (event, context) => {
  try {
    return await db.collection('user').where({
      done: true
    }).remove()
  } catch(e) {
    console.error(e)
  }
}

六、查询和更新数据/对象

我们可以对"对象、对象中的元素、数组、数组中的元素"进行匹配查询,甚至还可以对数组和对象相互嵌套的字段进行匹配查询/更新

6.1:普通匹配

传入的对象的每个 <key, value> 构成一个筛选条件,有多个 <key, value> 则表示需同时满足这些条件,是与的关系,如果需要或关系,可使用 command.or

案例1:如找出未完成的进度 50 的待办事项

javascript 复制代码
db.collection('user').where({
  done: false,
  progress: 50
}).get()

6.2:查询集合

查询集合中嵌套元素,假设在集合中有如下一个记录:

json 复制代码
{
  "style": {
    "color": "red"
  }
}

如果我们想要找出集合中 style.color 为 red 的记录,那么可以传入相同结构的对象做查询条件或使用 "点表示法" 查询:

javascript 复制代码
// 方式一
db.collection('todos').where({
  style: {
    color: 'red'
  }
}).get()

// 方式二
db.collection('todos').where({
  'style.color': 'red'
}).get()

6.3:查询数组(3种)

1、匹配数组

假设在集合中有如下一个记录:

json 复制代码
{
  "numbers": [10, 20, 30]
}

案例:可以传入一个完全相同的数组来筛选出这条记录:

javascript 复制代码
db.collection('todos').where({
  numbers: [10, 20, 30]
}).get()

2、匹配数组中的某个元素

(1)如果想找出数组字段中数组值包含某个值的记录,那可以在匹配数组字段时传入想要匹配的值。

假设在集合中有如下一个记录:

json 复制代码
{
  "numbers": [10, 20, 30]
}

案例:可传入一个数组中存在的元素来筛选出所有 numbers 字段的值包含 20 的记录:

javascript 复制代码
db.collection('todos').where({
  numbers: 20
}).get()

3、匹配数组第 n 项元素

如果想找出数组字段中数组的第 n 个元素等于某个值的记录,那在 <key, value> 匹配中可以以 "字段.下标" 为 key,目标值为 value 来做匹配。

假设在集合中有如下一个记录:

json 复制代码
{
  "numbers": [10, 20, 30]
}

案例(查询):如对上面的例子,如果想找出 number 字段第二项的值为 20 的记录,可以如下查询(注意:数组下标从 0 开始):

javascript 复制代码
db.collection('todos').where({
  'numbers.1': 20
}).get()

案例(更新):更新也是类似,比如我们要更新 _id 为 test 的记录的 numbers 字段的第二项元素至 30:

javascript 复制代码
db.collection('todos').doc('test').update({
  data: {
    'numbers.1': 30
  },
})

6.4:查询并更新数组中的元素(2种)

1. 更新数组中第一个匹配到的元素

更新数组字段的时候可以用 字段路径.$ 的表示法来更新数组字段的第一个满足查询匹配条件的元素。注意使用这种更新时,查询条件必须 包含该数组字段。

假如有如下记录:

json 复制代码
{
  "_id": "doc1",
  "scores": [10, 20, 30]
}
{
  "_id": "doc2",
  "scores": [20, 20, 40]
}

让所有 scores 中的第一个 20 的元素更新为 25:

javascript 复制代码
// 注意:批量更新需在云函数中进行
const _ = db.command
db.collection('todos').where({
  scores: 20
}).update({
  data: {
    'scores.$': 25
  }
})

如果记录是对象数组的话也可以做到,路径如 字段路径.$.字段路径。

注意事项:

  • 不支持用在数组嵌套数组
  • 如果用 unset 更新操作符,不会从数组中去除该元素,而是置为 null
  • 如果数组元素不是对象、且查询条件用了 neq、not 或 nin,则不能使用 $

2. 更新数组中所有匹配的元素

(1)更新数组字段的时候可以用 "字段路径.$[]" 的表示法来更新数组字段的所有元素。

假如有如下记录:

json 复制代码
{
  "_id": "doc1",
  "scores": {
    "math": [10, 20, 30]
  }
}

比如让 scores.math 字段所有数字加 10:更新后 scores.math 数组从 [10, 20, 30] 变为 [20, 30, 40]。

javascript 复制代码
const _ = db.command
db.collection('todos').doc('doc1').update({
  data: {
    'scores.math.$[]': _.inc(10)
  }
})

(2)如果数组是对象数组也是可以的,假如有如下记录:

json 复制代码
{
  "_id": "doc1",
  "scores": {
    "math": [
      { "examId": 1, "score": 10 },
      { "examId": 2, "score": 20 },
      { "examId": 3, "score": 30 }
    ]
  }
}

可以更新 scores.math 下各个元素的 score 原子自增 10:

javascript 复制代码
const _ = db.command
db.collection('todos').doc('doc1').update({
  data: {
    'scores.math.$[].score': _.inc(10)
  }
})

6.5:匹配多重嵌套的数组和对象

上面所讲述的所有规则都可以嵌套使用的,假设我们在集合中有如下一个记录:

json 复制代码
{
  "root": {
    "objects": [
      {
        "numbers": [10, 20, 30]
      },
      {
        "numbers": [50, 60, 70]
      }
    ]
  }
}

我们可以如下找出集合中所有的满足 root.objects 字段数组的第二项的 numbers 字段的第三项等于 70 的记录:

javascript 复制代码
db.collection('todos').where({
  'root.objects.1.numbers.2': 70
}).get()

注意,指定下标不是必须的,比如可以如下找出集合中所有的满足 root.objects 字段数组中任意一项的 numbers 字段包含 30 的记录:

javascript 复制代码
db.collection('todos').where({
  'root.objects.numbers': 30
}).get()

更新操作也是类似,比如我们要更新 _id 为 test 的 root.objects 字段数组的第二项的 numbers 字段的第三项 为 80:

javascript 复制代码
db.collection('todos').doc('test').update({
  data: {
    'root.objects.1.numbers.2': 80
  },
})

七、拓展知识点

7.1:云开发-command指令有哪些

javascript 复制代码
//连接云开发数据库
const db = wx.cloud.database();

//定义一个变量,用来使用command指令
const _ = db.command;

查询指令

javascript 复制代码
eq 	//严格相等,表示字段等于某值
neq //严格不相等,表示字段不等于某值
lt 	//表示小于某个值
lte //表示小于等于某个值
gt 	//表示大于某个值
gte //表示大于等于某个值

in 	//查询筛选条件,表示字段的值需在给定的数组内。
如:查找北京和上海的文章,article: _.in(["北京", "上海"])

and //查询指令,用于表示逻辑"与"的关系,表示需同时满足多个查询筛选条件。
如:查询16-19岁的人,age: _.gte(16).and(_.lte(19)) 或 _.and(_.gte(16), _.lte(30))

or  //查询指令,用于表示逻辑"或"的关系,表示需同时满足多个查询筛选条件。
  两种用法:
  1.可以进行字段值的"或"操作,比如获取年龄>18或者年龄<12的人,_.or(_.gt(18), _.lt(12))
  2.可以进行跨字段的"或"操作,且where()中无需写{},直接写where(_.or())即可
  如:获取2022年的文章或者标题中包含"2022"的文章:
	_.or([ { date: _.gte(new Date("2022-01-01")) }, { title: /2022/ } ])

更新指令

javascript 复制代码
set    //更新指令,用于设定字段等于指定值。
remove //更新指令,用于表示删除某个字段。
如:删除author对象中的age,author: { age: _.remove() }

inc    //更新指令,用于指示字段自增某个值,这是个原子操作,使用这个操作指令而不是先读数据、再加、再写回的好处是:
  1. 原子性:多个用户同时写,对数据库来说都是将字段+1,不会有后来者覆写前者的情况。
  2. 减少一次网络请求,不需要先读再写。
mul //更新指令,自乘,原理和inc一样。

数组处理相关指令:
push //更新指令,对一个值为数组的字段,往末尾添加一个或多个值,或字段原为空,则创建该字段并设为数组为传入值。
pop //新指令,对一个值为数组的字段,将数组末尾元素删除。
shif //更新指令,对一个值为数组的字段,将数组首位元素删除。
unshift //更新指令,对一个值为数组的字段,往首位添加一个或多个值。或字段原为空,则创建该字段并设为数组为传入值。
相关推荐
云和数据.ChenGuang5 小时前
Django 应用安装脚本 – 如何将应用添加到 INSTALLED_APPS 设置中 原创
数据库·django·sqlite
woshilys5 小时前
sql server 查询对象的修改时间
运维·数据库·sqlserver
Hacker_LaoYi5 小时前
SQL注入的那些面试题总结
数据库·sql
建投数据6 小时前
建投数据与腾讯云数据库TDSQL完成产品兼容性互认证
数据库·腾讯云
Hacker_LaoYi7 小时前
【渗透技术总结】SQL手工注入总结
数据库·sql
岁月变迁呀7 小时前
Redis梳理
数据库·redis·缓存
独行soc7 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍06-基于子查询的SQL注入(Subquery-Based SQL Injection)
数据库·sql·安全·web安全·漏洞挖掘·hw
你的微笑,乱了夏天8 小时前
linux centos 7 安装 mongodb7
数据库·mongodb
工业甲酰苯胺8 小时前
分布式系统架构:服务容错
数据库·架构
独行soc9 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍08-基于时间延迟的SQL注入(Time-Based SQL Injection)
数据库·sql·安全·渗透测试·漏洞挖掘