Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Cloud development storage, arrays, objects


May 22, 2021 Mini Program Cloud Development Study Guide


Table of contents


In the Cloud Development Capabilities section, we learned that small programs and service providers can upload files to cloud storage, but in real development, file links in cloud storage need to be recorded in a database for easy access. N ext, we will introduce how the addition and deletion of cloud storage files is combined with the addition and deletion of databases. The data types in the database we're involved in in the Getting Started with Cloud Database section are also very simple, and in this chapter we'll show you how to manipulate additions and additions to complex data types such as arrays and objects of the database.

The relationship between cloud storage and databases

Without the database directly upload the file to the cloud storage, so that the file upload, delete, modify, query can not correspond to the specific business, such as article merchandise drawings, form image attachments added and deleted, all need pictures and other resources can be directly related to the article, commodity, form ID can be managed (in the database can correspond), and these articles, goods, forms can be linked to the user's ID, other business, It can be seen that database plays an extremely important role in the management of cloud storage.

The design and structure of the database

In addition to Excel tables, relationship databases (such as MySQL) that design table structures with row and column, and multi-table relationships, cloud-developed databases are document-based. Instead of spreading it across multiple collections, we can nest multi-layer arrays and objects in a single record, embedding the data needed for each document into one document.

For example, we want to do a disk program, to record user information, as well as create albums, folders, here albums and folders because you can create many, so it is an array, and each album object and folder object can store a list of photos and files list, we found that in the cloud development database an element of the value is an array, arrays and nested objects, there are elements in the object is an array is very common.

The following is the database design of the net disk program, which contains a user's information, all uploaded files and photos and other information:

  1. {
  2. "_id": "自动生成的ID",
  3. "_openid": "用户在当前小程序的openid",
  4. "nickName": "用户的昵称",
  5. "avatarUrl": "用户的头像链接",
  6. "albums": [
  7. {
  8. "albumName": "相册名称",
  9. "coverURL": "相册封面地址",
  10. "photos": [
  11. {
  12. "comments": "照片备注",
  13. "fileID": "照片的地址"
  14. }
  15. ]
  16. }
  17. ],
  18. "folders": [
  19. {
  20. "folderName": "文件夹名称",
  21. "files": [
  22. {
  23. "name": "文件名称",
  24. "fileID": "文件的地址",
  25. "comments": "文件备注"
  26. }
  27. ]
  28. }
  29. ]
  30. }

If you use a relationship database, you will build a user table to store user information, albums table storage album information, folders table storage folder information, photos table storage photo information, files table storage file information, I believe you can use this case to the cloud database is document-oriented have a general understanding.

Of course, cloud-developed databases can also spread data across different collections, depending on the situation, which we'll cover later in the section. This practice of embedding the data required for each document into one document, known as denormalization, spreads the data across several different collections, which refer to each other as paradigmization, which means that the anti-paradigm document contains sub-documents, where as well as the sub-documents of the document are stored in another collection.

FileID is the link between storage and database

From the above can be seen, cloud storage and database is through fileID to get in touch, the database only records files in the cloud storage fileID, we can access the database corresponding fileID properties for record addition and deletion operations, while calling cloud storage upload files, download files, delete files and other APIs, so that cloud storage is managed by the database.

Opening all the APIs stored in the cloud development technology document, such as uploading files uploadFile, downloading files downloadFile, deleting files deleteFile, trading cloud file IDs for real link getTempFileURLs, we find that these APIs are always around fileID, either fileID is the object returned by the success callback, or fileID is a prerequisite for the API.

Establish a relationship between the user and the data

Openid and cloud development

As we've learned earlier, users have a unique openid in a small program that can distinguish users entirely, when using cloud development, users upload files to cloud storage on the applet, this openid is recorded in file information, and adding data to the database this openid is saved in the _openid field (that is, we can use cloud functions such as the previous login to get the user's openid, You can also get openid through the _openid field of the database, and when we query the data on the small terminal (the premise of query time change, deletion, update, etc.), there is a condition of where (_openid: the current user's openid) by default, limiting the user's right to write (change, delete, update).

_id and cloud development

When a user adds a record document to a database on a small program end with a Collection.add, _id is automatically generated for that record, and a _openid,_id and _openid are created because they are unique, as long as we get the record _id created by each user, we can also determine the user's openid.

Determine if the user exists and create a record

Open the database tab for the cloud development console, create a new collection of clouddisks, and modify its permissions to read for everyone, readable and write-only for creators (or use security rules). Use the developer tool to create a newfolder page, and then enter .js code in the page lifecycle function onLoad of the tool:

  1. this.checkUser()

This calls a custom function, and developers can add any function or data to the Object parameter, which can be accessed in the function of the page

Then enter the following code in the Page() object, which means that if there is no user-created data in clouddisk, a new record is added in clouddisk;

  1. async checkUser() {
  2. //获取clouddisk是否有当前用户的数据,注意这里默认带了一个where({_openid:"当前用户的openid"})的条件
  3. const userData = await db.collection('clouddisk').get()
  4. console.log("当前用户的数据对象",userData)
  5. //如果当前用户的数据data数组的长度为0,说明数据库里没有当前用户的数据
  6. if(userData.data.length === 0){
  7. //没有当前用户的数据,那就新建一个数据框架,其中_id和_openid会自动生成
  8. return await db.collection('clouddisk').add({
  9. data:{
  10. //nickName和avatarUrl可以通过getUserInfo来获取,这里不多介绍
  11. "nickName": "",
  12. "avatarUrl": "",
  13. "albums": [ ],
  14. "folders": [ ]
  15. }
  16. })
  17. }else{
  18. this.setData({
  19. userData
  20. })
  21. console.log('用户数据',userData)
  22. }
  23. },

A user can only create one record, and if one user opens, the user can create multiple records...

A pre-documented data framework makes it easy for us to update the data in a update way later.

Instructions for the use of async/await

Async is a short case of "asynchronous", async is used to state that a function is asynchronous, while await is used to wait for an asynchronous method execution to complete, and await can only appear in the async function. a wait is only valid in the async function. Assuming that a business needs to be completed step by step, each step is asynchronous, and depends on the results of the previous step, or even on the results of each previous step, you can use Async Await to do so

The small terminal now fully supports async/await writing, but needs to be set up locally in the developer tool-details, check Enhanced Compilation, otherwise the following errors will be reported.

  1. Uncaught ReferenceError: regeneratorRuntime is not defined

The value returned by the async function is the Promise object, and the value returned by the return inside the async function. b ecomes an argument to the then method callback function. I f an exception is thrown inside the async function, the returned Promise object state becomes reject. T he thrown error is received by the catch method callback function. T he Promise object returned by the async function must wait until all the Promise objects of the internal await command have been executed before a state change occurs. That is, the callback to the then method is performed only when the asynchronous operations inside the async function have been performed.

Using await in the async function, the code here becomes synchronized, meaning that only when the Promise execution behind the await is complete will the results continue, await is waiting, so that although it avoids asynchronous, but it also blocks the code, so when using it to consider carefully. await blocks the code, and each await must wait for the subsequent fn() execution to complete before executing the next line of code

Cloud storage folder management

To create a folder on the small terminal, there are three aspects to consider, one is how the folder is created in the cloud storage, the other is the representation of the folder in the database, and the third is how the small terminal page should interact to create a folder;

How folders are created in cloud storage

In the cloud development capabilities section we learned that to upload demo.jpg to the cloud storage cloudbase folder, just indicate that the path of cloudPath cloud storage is cloudbase/demo.jpg can be, here the cloudbase folder, when we upload files the code is automatically created, that is, we create folders on the small terminal do not need to do anything to cloud storage, because here in the cloud storage, folders are only created when files are uploaded.

The form of the folder in the database

Although the page interaction of a folder on the small terminal seems very complex, it looks very simple in the form of a database, we create folders just to manipulate (add and delete) arrays and objects, the following array offolders is a list of folders, and a folder is just an object in an array.

  1. "folders": [
  2. {
  3. "folderName": "文件夹名称",
  4. "files": [ ]
  5. }
  6. ]

The creation of the folder interacts with the page

From the previous analysis, we can see that creating folders on the small terminal will only manipulate the data of the database, not cloud storage, and let's look at the specific code implementation. Use the developer tool to create a newfolder page and enter the following code in thefolder.wxml:

  1. <form bindsubmit="formSubmit">
  2. <input name="name" placeholder='请输入文件夹名' auto-focus value='{{inputValue}}' bindinput='keyInput'></input>
  3. <button type="primary" formType="submit">新建文件夹</button>
  4. </form>

Method one: Use push and

Enter the following .js in the holder::

  1. async createFolder(e) {
  2. let foldersName = e.detail.value.foldersName
  3. const folders = this.data.userData.data[0].folders
  4. folders.push({ foldersName: foldersName, files: [] })
  5. const _id= this.data.userData.data[0]._id
  6. return await db.collection('clouddisk').doc(_id).update({
  7. data: {
  8. folders: _.set(folders)
  9. }
  10. })
  11. },

Technical documentation: Field update operator set

Method two:

Enter the following .js in the holder::

  1. async createFolder(e) {
  2. let foldersName = e.detail.value.foldersName
  3. const _id= this.data.userData.data[0]._id
  4. return await db.collection('clouddisk').doc(_id).update({
  5. data: {
  6. folders: _.push([{ foldersName: foldersName, files: [] }])
  7. }
  8. })
  9. },

Technical documentation: Array update operator push

Read first, write first, write first, read later

Upload a single file to a folder

I believe that everyone should have experienced the function of file upload in other small programs, which may seem simple in interaction, but logically contains four key steps in the code:

  • First upload the file to the temporary file of the small program, and get the temporary file address and the name of the file;
  • Upload the temporary file to the designated cloud file in the cloud storage and q to the FileID of the file;
  • Upload the fileID and the name of the file stored in the cloud to the database;
  • Get information about all the files in the folder.

Upload files to temporary files for small programs

Use the developer tool to enter the following code infolder.wxml:

  1. <form bindsubmit="uploadFiles">
  2. <button type="primary" bindtap="chooseMessageFile">选择文件</button>
  3. <button type="primary" formType="submit">上传文件</button>
  4. </form>

Then enter .js code in the holder:

  1. chooseMessageFile(){
  2. const files = this.data.files
  3. wx.chooseMessageFile({
  4. count: 5,
  5. success: res => {
  6. console.log('选择文件之后的res',res)
  7. let tempFilePaths = res.tempFiles
  8. for (const tempFilePath of tempFilePaths) {
  9. files.push({
  10. src: tempFilePath.path,
  11. name: tempFilePath.name
  12. })
  13. }
  14. this.setData({ files: files })
  15. console.log('选择文件之后的files', this.data.files)
  16. }
  17. })
  18. },

Upload temporary files to cloud storage

Technical documentation: wx.cloud.uploadFile

  1. uploadFiles(e) {
  2. const filePath = this.data.files[0].src
  3. const cloudPath = `cloudbase/${Date.now()}-${Math.floor(Math.random(0, 1) * 1000)}` + filePath.match(/\.[^.]+?$/)
  4. wx.cloud.uploadFile({
  5. cloudPath,filePath
  6. }).then(res => {
  7. this.setData({
  8. fileID:res.fileID
  9. })
  10. }).catch(error => {
  11. console.log("文件上传失败",error)
  12. })
  13. },

When the upload is successful, you get a unique identifier for the file, the file ID, and subsequent actions are based on the file ID rather than the URL.

Store file information to the database

  1. addFiles(fileID) {
  2. const name = this.data.files[0].name
  3. const _id= this.data.userData.data[0]._id
  4. db.collection('clouddisk').doc(_id).update({
  5. data: {
  6. 'folders.0.files': _.push({
  7. "name":name,
  8. "fileID":fileID
  9. })
  10. }
  11. }).then(result => {
  12. console.log("写入成功", result)
  13. wx.navigateBack()
  14. }
  15. )
  16. }

Match array item n Element If you want to find out that the nth element of the array in the array field is equal to a record of a value, you can use the field in the match. T he underse mark is key and the target value is value to match. For example, if you want to find a record with a value of 20 for the second item in the number field, you can query as follows (note: array subsequencing starts at 0)

Gets a list of files in the folder

Enter in the onload lifecycle function

  1. this.getFiles()

Then add the getFiles() method to the Page object to get the user's data

  1. getFiles(){
  2. const _id= this.data.userData.data[0]._id
  3. db.collection("clouddisk").doc(_id).get()
  4. .then(res => {
  5. console.log('用户数据',res.data)
  6. })
  7. .catch(err => {
  8. console.error(err)
  9. })
  10. }

To actually develop a specific function, we must first think about this function of the page interaction is how, and the page interaction behind is only simple data, but it is these simple data after page interaction processing but "blind" the user's eyes, so that users feel complex, feel that this function is real.

A query that nests arrays and objects

We can match objects, elements in objects, arrays, elements in arrays, and even match queries/updates to fields where arrays and objects are nested with each other

Match nested fields in a record

  1. // 方式一
  2. db.collection('todos').where({
  3. style: {
  4. color: 'red'
  5. }
  6. }).get()
  7. // 方式二
  8. db.collection('todos').where({
  9. 'style.color': 'red'
  10. }).get()

Matches and updates the elements in the array

Upload multiple files to a folder

Query all the data

  1. const cloud = require('wx-server-sdk')
  2. cloud.init({
  3. env: cloud.DYNAMIC_CURRENT_ENV
  4. })
  5. const db = cloud.database()
  6. const MAX_LIMIT = 100
  7. exports.main = async (event, context) => {
  8. // 先取出集合记录总数
  9. const countResult = await db.collection('china').count()
  10. const total = countResult.total
  11. // 计算需分几次取
  12. const batchTimes = Math.ceil(total / 100)
  13. // 承载所有读操作的 promise 的数组
  14. const tasks = []
  15. for (let i = 0; i < batchTimes; i++) {
  16. const promise = db.collection('china').skip(i * MAX_LIMIT).limit(MAX_LIMIT).get()
  17. tasks.push(promise)
  18. }
  19. // 等待所有
  20. return (await Promise.all(tasks)).reduce((acc, cur) => {
  21. return {
  22. data: acc.data.concat(cur.data),
  23. errMsg: acc.errMsg,
  24. }
  25. })
  26. }

The small terminal downloads and previews the file

Technical documentation: wx.openDocument(), wx.cloud.downloadFile

Using cloud development to download files from cloud storage, there will be no domain name verification filing issues

  1. previewFile(){
  2. wx.cloud.downloadFile({
  3. fileID: 'cloud://xly-xrlur.786c-xly-xrlur-1300446086/cloudbase/技术工坊预备手册.pdf'
  4. }).then(res => {
  5. const filePath = res.tempFilePath
  6. wx.openDocument({
  7. filePath: filePath
  8. })
  9. }).catch(error => {
  10. console.log(error)
  11. })
  12. }

Delete records and delete fields

Technical documentation: deleteFile

Files can be downloaded based on the file ID, and users can only download files that they have access to:

  1. const cloud = require('wx-server-sdk')
  2. cloud.init({
  3. env: cloud.DYNAMIC_CURRENT_ENV
  4. })
  5. exports.main = async (event, context) => {
  6. const fileIDs = ['xxx', 'xxx']
  7. const result = await cloud.deleteFile({
  8. fileList: fileIDs,
  9. })
  10. return result.fileList
  11. }

Nested delete fields

  1. return await db.collection("clouddisk").doc("_id").update({
  2. data:{
  3. "folders.0.files.1": _.remove()
  4. }
  5. })

Get temporary links and share files

Technical documentation: getTempFileURL

Pass the files on the service side to the small terminal

Technical documentation: downloadFile