Added in HBuilderX 3.5.2, need to activate redis

# JQL Cache Redis

uniCloud provides two kinds of databases: MongoDB and Redis. And provides a linkage mechanism, which can easily cache the data in MongoDB into Redis.

Applicable scene:

Data that needs to be accessed frequently, but not frequently modified. For example, public data such as infrequently updated homepage lists, banners, hot searches, and top rankings.

The frequency of these query requests is high. If you go to MongoDB to read each time, it is slow and expensive, and it may timeout or exceed concurrency.

Using JQL Cache Redis, you can easily cache these query results in Redis. It not only improves the access speed, but also improves the concurrent performance, and also reduces the running time of cloud functions and the number of database reads.

  • JQL Cache Redis can be used regardless of clientDB components or API, or cloud function/cloud object JQL
  • But JQL manager does not support, this debugging tool can only query MongoDB directly
  • To use JQL Cache Redis in cloud functions/cloud objects, you need to load Redis and JQL extension libraries and rely on the uni-config-center public module
  • Local operation is also supported

# Principle

  1. The developer configures the specified JQL query command in uni-config-center
  2. When the client or cloud function performs a JQL query, it will determine whether the current command is configured in advance
    • 2.1 If not configured, continue to connect to MongoDB with normal query
    • 2.2 If configured, go to Redis to get query results
      • 2.2.1 If the result is found in Redis, return the query result
      • 2.2.2 If it is found that there is no cached result in Redis or the cache has expired, connect the MongoDB query again, and automatically synchronize the result to Redis while returning the query result. You can go to Redis next time you visit.
  3. If the developer updates the data in MongoDB, the API needs to be called to invalidate the specified cache in Redis see below

# 配置方法

uniCloud/cloudfunctions/common/uni-config-center下创建uni-jql-cache-redis.json文件(注意此文件是标准json格式,不支持注释)

If uni-config-center is not installed, please import it in the plugin market, the plugin address: uni-config-center

The uni-jql-cache-redis.json file is an array where each item is a cache configuration. The example content is as follows

[{
	"id": "test-get", // 缓存id,不可重复,必填
	"jql": "db.collection('test').limit(10).get()", // 要缓存的数据库指令,必填
	"expiresIn": 3600 // 缓存有效期,单位秒,非必填
}]

expiresIn is the cache validity period, in seconds. The start time of the validity period is the time from the first cache to redis (in fact, the validity period that comes with redis). If not filled, it means that it will not expire according to time.

After the configuration is successful, when the client or cloud JQL queries db.collection('test').limit(10).get(), it will first go to redis to find it. If it is not found, it will find it from MongoDB and then automatically cache into redis.

When the cache is hit, clientDB or cloud functions/cloud objects using the jql extension will output the following logs

"当前请求需使用Redis缓存" 
"返回Redis内缓存的结果" 

When the cache is missed, clientDB or cloud functions/cloud objects using the jql extension will output the following logs

"当前请求需使用Redis缓存" 
"未命中Redis缓存,设置Redis缓存" 

JQL Cache Redis will cache the query results corresponding to the cache configuration in the redis cache whose key is unicloud:jql-cache:${id}:string. It can be found in the redis view of the uniCloud web console.

When configuring "jql": "db.collection('test').limit(10).get()", please note that the quotation marks need to be escaped when placing ordinary JQL statements in the value of json, see below.

# About quote escaping

Since the query statement needs to be placed in the json file, and the strings in the json need to be surrounded by quotation marks, the scenarios that use double quotation marks in the query statement need to be escaped and then placed in the configuration.

E.g:

// jql
db.collection('book').where('author=="caoxueqin"').get()

// after escaping
"db.collection('book').where('author==\"caoxueqin\"').get()"

If your query statement is more complex, it is more troublesome to add escape characters one by one. The escaped string can be obtained as follows

  1. Create a cloud function as follows
'use strict';
const fs = require('fs')
const path = require('path')
exports.main = async (event, context) => {
  console.log(
	fs.readFileSync(
	  path.resolve(__dirname, 'test.jql')
	).toString()
  )
};
  1. Create a test.jql file in the cloud function root directory, the content is the jql query statement to be escaped
db.collection('book').where('author=="caoxueqin"').get()
  1. Run the cloud function locally and view the cloud function log output in the HBuilderX console
21:56:44.135 [本地运行]"db.collection('book').where('author==\"caoxueqin\"').get()" uniCloud-aliyun/cloudfunctions/test/index.js:5:10

# Precautions

  • Only JQL commands that can be queried can be cached, adding, deleting or modifying JQL commands is invalid
  • Uncacheable queries using cloud environment variables starting with db.getCloudEnv() or $cloudEnv_
  • Do not cache queries that use actions
  • Cloud functions/cloud objects that enable the JQL extension library must also enable the Redis extension library to use the cache function normally, otherwise they will still be queried from the database
  • After configuration or setting cache invalidation, developers can request a JQL query by themselves to make the cache take effect. Avoid users still accessing MongoDB the first time they access
  • If there are strings using quotation marks in the query statement, please ensure that single and double quotation marks are consistent with the configured cache, for example: the cache configuration is written in double quotation marks: .where('name=="caoxueqin"'), the escaped single quote is used when calling, .where('name==\'caoxueqin\''), then this call query will not go to the redis cache. Subsequent optimization of this problem

##multiSend uses cache @multi-send

When using multiSend to send multiple instructions at the same time, caching the entire multiSend is not supported. Each instruction needs to be cached separately.

example:

const book = db.collection('book').limit(10).getTemp()
const author = db.collection('author').limit(10).getTemp()
db.multiSend(book,author)

For the above database directives, you cannot directly configure jql in the cache configuration as const book = db.collection('book').limit(10).getTemp();const author = db.collection('author').limit( 10).getTemp();db.multiSend(book,author)

You need to configure the query statement of the book table and the query statement of the author table separately. Note that the getTemp method also needs to be changed to the get method.

[{
	"id": "book-get",
	"jql": "db.collection('book').limit(10).get()",
	"expiresIn": 3600
}, {
	"id": "author-get",
	"jql": "db.collection('author').limit(10).get()",
	"expiresIn": 3600
}]

# Joint table query

The cache statement configured when joining the table is also consistent with the jql syntax

example:

const book = db.collection('book').limit(10).getTemp()
const author = db.collection('author').getTemp()
db.collection(book, author).get()

uni-jql-cache-redis.json cache configuration is as follows

[{
	"id": "book-author-lookup",
	"jql": "const book = db.collection('book').limit(10).getTemp();const author = db.collection('author').getTemp();db.collection(book, author).get()",
	"expiresIn": 3600
}]

# delete redis cache

When the data in MongoDB changes, the cache in Redis should be actively deleted.

For example, after caching the data of the banner carousel in Redis, and modifying the banner in the admin, you should operate redis in the cloud function at the same time, and set the banner cache to invalid

Use the redis delete command to pass in the key corresponding to the cache to delete the cache.

example:

const redis = uniCloud.redis()
const id = 'banner' // 这个id就是`uni-jql-cache-redis.json`中配置的id
const cacheKey = `unicloud:jql-cache:${id}:string`
await redis.del(cacheKey)