Trong bài đăng này, chúng tôi sẽ xây dựng một ứng dụng di động không có máy chủ với Flutter, Serverless Framework, Upstash và Redis để lưu trữ dữ liệu.
Upstash là gì?
Upstash là một Cơ sở dữ liệu không máy chủ cho Redis. Với Upstash, bạn trả tiền theo yêu cầu. Điều này có nghĩa là bạn không bị tính phí khi cơ sở dữ liệu không được sử dụng.
Upstash định cấu hình và quản lý cơ sở dữ liệu cho bạn. Đây là một giải pháp thay thế mạnh mẽ cho các cơ sở dữ liệu khác như DynamoDB và Fauna, với các ưu điểm như
- độ trễ thấp
- Dễ sử dụng, giống như API REDIS.
Đây là tài liệu chi tiết so sánh Upstash với các giải pháp dựa trên đám mây thay thế, cung cấp cho bạn lý do rõ ràng về lý do tại sao bạn nên chọn nó cho dự án tiếp theo của mình.
Bạn cũng có thể xem bài viết này để so sánh tất cả các cơ sở dữ liệu serverless hiện có
Với Upstash,
- Bạn bắt đầu miễn phí và chỉ trả tiền cho những gì bạn sử dụng
- Nó có bộ nhớ nhanh, bền
- Bạn có thể truy cập cơ sở dữ liệu của mình từ mọi nơi trên toàn cầu với độ trễ thấp do Cơ sở dữ liệu toàn cầu và Edge Caching.
Bắt đầu Upstash miễn phí ngay hôm nay
Để xây dựng hiệu quả các ứng dụng trên Upstash, bạn phải hiểu về Redis.
Nếu bạn thích thứ gì đó chi tiết và chuyên sâu hơn, tôi khuyên bạn nên sử dụng Trang web chính thức của Redis
Redis là một kho lưu trữ cấu trúc dữ liệu trong bộ nhớ, mã nguồn mở (được cấp phép BSD), được sử dụng làm cơ sở dữ liệu, bộ nhớ cache và môi giới tin nhắn.
Nó hỗ trợ rất nhiều cấu trúc dữ liệu như
- chuỗi
- băm
- danh sách
- bộ
- tập hợp được sắp xếp với các truy vấn phạm vi
- ảnh bitmap
- siêu nhật ký
- chỉ mục không gian địa lý
Bạn tương tác với cơ sở dữ liệu Redis bằng cách sử dụng các lệnh và lưu dữ liệu ở định dạng giá trị khóa, trong đó khóa có thể là một chuỗi và giá trị, bất kỳ cấu trúc dữ liệu nào được Redis hỗ trợ.
Ví dụ:tôi có thể sử dụng lệnh Redis SET
để lưu trữ giá trị họ của tôi như vậy
SET surname Rosius
nơi surname
là khóa và Rosius là giá trị.
Một điều rất quan trọng cần lưu ý với Redis là luôn lưu trữ dữ liệu của bạn theo cách mà bạn có thể dễ dàng truy xuất.
Không có cách trực tiếp nào để tìm kiếm khóa theo giá trị trong Redis.
Dữ liệu trong Redis được lưu trữ vĩnh viễn. Vì vậy, tôi có thể truy xuất dữ liệu được lưu trữ tại khóa surname
như vậy
GET surname
Kết quả đến 'Rosius'
Chúng tôi cũng có thể xóa giá trị được lưu trữ tại khóa surname
như vậy
DEL surname
Giả sử chúng tôi muốn tăng lượt thích của một bài đăng. Đây là cách chúng tôi có thể dễ dàng làm điều đó, sử dụng INCR
lệnh nguyên tử.
SET likes 10
INCR likes => 11
INCR likes => 12
INCR likes => 13
Đầu tiên, chúng tôi đặt giá trị ban đầu của lượt thích là 10, sau đó chúng tôi tăng nguyên tử giá trị của lượt thích. Bây giờ, bạn có thể nghĩ rằng cũng có thể tăng likes
theo cách này.
x = GET likes
x = x + 1
SET likes x
Điều này hoàn toàn ổn, miễn là bạn là người duy nhất sử dụng ứng dụng của mình.
Khi có> 2 người tăng lên giống như vậy, quá trình trên (GET, Increment, SET) không còn là nguyên tử nữa. Vì vậy,
x = GET likes (yields 10)
y = GET likes (yields 10)
x = x + 1 (x is now 11)
y = y + 1 (y is now 11)
SET likes x (likes is now 11)
SET likes y (likes is now 11
Từ đoạn mã trên, người dùng 1 nhận giá trị của lượt thích là 10 và lưu trữ nó trong một biến x, đồng thời, người dùng 2 nhận cùng giá trị lượt thích đó, cũng là 10 và lưu trữ nó trong một biến y.
Người dùng 1 thêm 1 vào giá trị của lượt thích (x) và đặt giá trị mới, hiện là 11.
Người dùng 2 cũng làm như vậy.
Vì vậy, giá trị của lượt thích là 11.
Nhưng điều đó có thực sự chính xác? Hãy nhớ rằng số lượt thích đã được tăng gấp đôi bởi 2 người dùng khác nhau.
Giá trị của lượt thích phải là 12 chứ không phải 11. Đó là lý do tại sao Redis cung cấp INCR
lệnh nguyên tử và giải quyết các vấn đề như vậy.
Hash DataType
Các hàm băm của Redis tương đương với các hàm băm của các ngôn ngữ lập trình khác. Về cơ bản, chúng được tạo thành từ một tập hợp các trường được liên kết với các giá trị:
Ví dụ, đây là cách tôi sẽ lưu trữ thông tin hồ sơ người dùng trong một Hash.
HMSET userProfile:100034 "userId" 100034 "username" "Rosius Ndimofor"
"firstName" "Rosius" "lastName" "Ndimofor" "profilePic" "rosius.jpeg"
Thứ nhất, khóa cho Hash của chúng tôi là userProfile:100034
, thì chúng ta có key value
tất cả các cặp thông qua. Ví dụ:"userId"
là khóa và 100034' is the value. We can retrieve specific user profile information such as first name by using the
Lệnh HGET command and
userId` như vậy.
userId = 100034
HGET userProfile:{userId} firstName
Hoặc Chúng tôi có thể truy xuất tất cả thông tin hồ sơ người dùng cho một người dùng cụ thể bằng cách sử dụng GETALL
lệnh như vậy
userId = 100034
HGETALL userProfile:{userId}
Loại dữ liệu danh sách
Trước đó, tôi đã nói rằng, trong Redis, điều rất quan trọng là phải lưu dữ liệu theo cách bạn định truy xuất.
Điều gì sẽ xảy ra nếu chúng tôi muốn có được tất cả người dùng trên nền tảng của mình?
Chúng tôi vừa sử dụng cấu trúc dữ liệu Hash để lưu thông tin hồ sơ người dùng. Bây giờ chúng tôi cần có được tất cả người dùng trên hệ thống của chúng tôi.
Cách dễ nhất để thực hiện điều này là lưu userId của mọi người dùng trong một Danh sách bằng cách sử dụng lệnh LPUSH (viết tắt của Left Push) như vậy
LPUSH "users" userId
Lấy tất cả người dùng từ Danh sách của chúng tôi, chúng tôi sử dụng lệnh LRANGE
như vậy
LRANGE "users" 0 -1
Đây chỉ là một vài lệnh mà chúng tôi sẽ sử dụng trong ứng dụng của mình. Nhưng tôi khuyến khích bạn truy cập trang web chính thức của Redis để xem phần còn lại của các lệnh và tìm hiểu cách sử dụng chúng.
Vậy ứng dụng full-stack của chúng ta hoạt động như thế nào?
Tôi rất vui vì bạn đã hỏi. Vì vậy, hôm nay, chúng ta sẽ bắt đầu bằng cách tạo API CRUD. Đây là trường hợp sử dụng.
Chúng tôi có 2 thực thể. Users
và Posts
.
Họ chia sẻ một mối quan hệ một đến nhiều. Vì vậy, một người dùng có thể có nhiều bài đăng và một bài đăng chỉ có thể thuộc về một người dùng.
Người dùng được phép
- Tạo một tài khoản. Không có chứng thực. Bạn có thể thêm xác thực bằng AWS Cognito hoặc Auth0.
- Cập nhật Tài khoản của họ
- Nhận tài khoản của họ
- Tạo một bài đăng
- Cập nhật bài đăng
- Thích một bài đăng
- Nhận danh sách tất cả các bài đăng
Đây là chế độ xem kiến trúc giải pháp
Vì vậy, hãy bắt đầu.
Tạo tài khoản Upstash
Vui lòng tạo một tài khoản Upstash miễn phí tại đây Đăng nhập Upstash.
Sau khi tạo tài khoản, hãy tạo cơ sở dữ liệu Upstash.
Bạn chỉ được phép tạo một cơ sở dữ liệu trong cấp miễn phí.
Lưu ý điểm cuối cơ sở dữ liệu Redis của bạn. Nó sẽ trông giống như thế này. rediss://:2c9bb162c2444bf7ab689640bb2ead23@gusc1-smashing-bee-30249.upstash.io:00049
Tạo dự án không máy chủ
Điều kiện tiên quyết
Vui lòng cài đặt các phần phụ thuộc này trước khi tiếp tục
-
AWS CLI
-
NodeJS
-
CLI không máy chủ
Tạo một dự án không máy chủ mới bằng cách sử dụng lệnh bên dưới và làm theo lời nhắc.
serverless
Chọn API nodejs HTTP, đặt tên cho dự án của bạn và nhấn enter
.
Đây là cấu trúc ban đầu của dự án không máy chủ của tôi.
Bên trong thư mục đó, khởi tạo một dự án nút mới bằng lệnh
npm init
Tiếp theo, cài đặt ứng dụng redis với
npm install ioredis
Ngoài ra, hãy cài đặt phụ thuộc Mã định danh duy nhất (uuid) phổ biến. Chúng tôi sẽ sử dụng nó rộng rãi trong dự án này.
npm install uuid
Bây giờ, hãy thêm Điểm cuối cơ sở dữ liệu Redis của bạn làm biến môi trường trong serverless.yml
tệp như vậy.
provider:
name: aws
region: us-east-1
stage: dev
runtime: nodejs12.x
lambdaHashingVersion: "20201221"
environment:
REDIS_CLIENT: "rediss://:2c9bb162c2444bf7ab689640bb2ead23@gusc1-smashing-wasp-30249.upstash.io:30249"
Tiếp theo, Tạo 2 thư mục bên trong dự án của bạn được gọi là users
và posts
. Cả hai thư mục này sẽ chứa các hàm lambda cho các trường hợp sử dụng tương ứng của chúng.
Hãy bắt đầu tạo các enpoint API của chúng ta
Tạo người dùng
Chúng tôi muốn người dùng có thể tạo một tài khoản cho chính họ.
Không có chứng thực. Tất cả những gì họ phải làm là gửi
- tên người dùng
- tên
- họ
- ảnh hồ sơ
Tạo tệp trong users
thư mục có tên create.js
.
Ở đầu tệp, nhập và khởi tạo ứng dụng khách redis bằng cách sử dụng URL cơ sở dữ liệu redis mà chúng tôi đã lưu dưới dạng biến môi trường trong serverless.yml
tệp.
"use strict";
const uuid = require("uuid");
var Redis = require("ioredis");
if (typeof client === "undefined") {
var client = new Redis(process.env.REDIS_CLIENT);
}
Chúng tôi cũng nhập phần phụ thuộc uuid, vì chúng tôi sẽ sử dụng nó để tạo ID duy nhất cho người dùng.
Đầu tiên, chúng ta cần một cấu trúc dữ liệu để lưu user profile
thông tin và một cấu trúc dữ liệu khác để lưu userId's
của tất cả người dùng trong ứng dụng.
Nhớ kiểu dữ liệu băm và danh sách?
Kiểu dữ liệu băm để lưu thông tin hồ sơ người dùng. Lưu ý về khóa kiểu dữ liệu userItem:${userId}
await client.hmset(
`userItem:${userId}`,
"userId",
userId,
username,
data.username,
firstName,
data.firstName,
lastName,
data.lastName,
profilePic,
data.profilePic,
"timestamp",
timestamp
);
Sau đó, chúng tôi lưu userId
đã tạo vào danh sách có tên users
await client.lpush("users", userId);
Nếu bạn nhận thấy, chúng tôi phải gửi 2 hoạt động. Có thể gửi chúng lần lượt, nhưng điều đó không tối ưu.
Upstash hỗ trợ các hoạt động hàng loạt, thông qua một tính năng được gọi là pipelining
.
Vì vậy, thay vì gửi các lệnh đơn lẻ và chờ phản hồi, chúng ta có thể gửi nhiều lệnh và phản hồi sẽ quay lại giống như cách chúng ta đã gửi các lệnh.
Vì vậy, đây là cách hoạt động của chúng tôi sẽ như thế nào sau khi sử dụng đường ống dẫn
client.pipeline(
await client.hmset(
`userItem:${userId}`,
"userId",
userId,
username,
data.username,
firstName,
data.firstName,
lastName,
data.lastName,
profilePic,
data.profilePic,
"timestamp",
timestamp
),
await client.lpush("users", userId)
);
Sau đó, chúng tôi có thể lấy tất cả thông tin hồ sơ người dùng lưu và gửi lại dưới dạng phản hồi thông qua api-gateway
.
//get and display saved user item
const userItem = await client.hgetall(`userItem:${userId}`);
Đừng quên cập nhật serverless.yml
để phản ánh điểm cuối này.
functions:
createUser:
handler: user/create.createUser
events:
- http:
path: /user
method: post
Tên hàm của chúng tôi là createUser
và nó nằm trong một tệp có tên là create.js
nằm trong thư mục có tên user
.Do đó trình xử lý user/create.createUser
.
Ghi lại đường dẫn /user
createUser
hàm sử dụng post
Phương thức http.
Đây là mã hoàn chỉnh cho users/create.js
tệp
"use strict";
const uuid = require("uuid");
var Redis = require("ioredis");
const username = "username";
const firstName = "firstName";
const lastName = "lastName";
const profilePic = "profilePic";
if (typeof client === "undefined") {
var client = new Redis(process.env.REDIS_CLIENT);
}
/**
*
* @param {username,firstName,lastName,profilePic} event
* @returns
*/
module.exports.createUser = async (event) => {
const timestamp = new Date().getTime();
const data = JSON.parse(event.body);
if (data == null) {
return {
statusCode: 400,
body: JSON.stringify(
{
message: "Couldn't create the user item",
},
null,
2
),
};
}
const userId = uuid.v1();
console.log(`userId is ${userId}`);
// here, we use a pipeline to perform multiple requests
// Firstly, we save the user details to a hash dataset with key (`userItem:${userId}`)
//
client.pipeline(
await client.hmset(
`userItem:${userId}`,
"userId",
userId,
username,
data.username,
firstName,
data.firstName,
lastName,
data.lastName,
profilePic,
data.profilePic,
"timestamp",
timestamp
),
await client.lpush("users", userId)
);
//get and display saved user item
const userItem = await client.hgetall(`userItem:${userId}`);
console.log(userItem);
return {
statusCode: 200,
body: JSON.stringify(userItem),
};
};
Cập nhật người dùng
Người dùng muốn cập nhật hồ sơ của họ theo thời gian. Vì vậy, đúng là chúng tôi cung cấp một điểm cuối cập nhật người dùng.
Lệnh duy nhất chúng ta cần cho thao tác này là HMSET
và userId
.
Từ tài liệu Redis, đây chính xác là cách HMSET
lệnh hoạt động.
Đặt các trường được chỉ định thành các giá trị tương ứng của chúng trong hàm băm được lưu trữ tại khóa. Lệnh này ghi đè bất kỳ trường cụ thể nào đã tồn tại trong hàm băm.
Đây là cách mã trông như thế nào.
"use strict";
const uuid = require("uuid");
var Redis = require("ioredis");
const username = "username";
const firstName = "firstName";
const lastName = "lastName";
if (typeof client === "undefined") {
var client = new Redis(process.env.REDIS_CLIENT);
}
/**
*
* @param {username,firstName,lastName,age,profilePic} event
* @returns
*/
module.exports.updateUser = async (event) => {
const timestamp = new Date().getTime();
const userId = event.pathParameters.id;
const data = JSON.parse(event.body);
if (userId == null) {
return {
statusCode: 400,
body: JSON.stringify(
{
message: "Couldn't update the user item",
},
null,
2
),
};
}
//get
await client.hmset(
`userItem:${userId}`,
username,
data.username,
firstName,
data.firstName,
lastName,
data.lastName
);
//get and display saved user item
const userItem = await client.hgetall(`userItem:${userId}`);
console.log(userItem);
return {
statusCode: 200,
body: JSON.stringify(userItem),
};
};
Sau đó, trong serverless.yml
tệp, dưới các chức năng, thêm ...
updateUser:
handler: user/update.updateUser
events:
- http:
path: /user/{id}
method: put
Chúng tôi chuyển userId
dưới dạng tham số đường dẫn /user/{id}
Nhận người dùng
Sử dụng HGETALL
và khóa băm, chúng tôi có thể lấy thông tin hồ sơ người dùng cho một người dùng cụ thể.
Hãy nhớ rằng chúng ta cũng có thể sử dụng HGET
lệnh để lấy thông tin người dùng cụ thể như firstName hoặc lastName, v.v.
Hãy xem mã
Tạo tệp trong users
thư mục có tên get.js
"use strict";
var Redis = require("ioredis");
if (typeof client === "undefined") {
var client = new Redis(process.env.REDIS_CLIENT);
}
module.exports.getUserById = async (event) => {
const userId = event.pathParameters.id;
if (userId == null) {
return {
statusCode: 400,
body: JSON.stringify(
{
message: "Couldn't get the user item",
},
null,
2
),
};
}
console.log(`userId is ${userId}`);
//get and display saved user item
const userItem = await client.hgetall(`userItem:${userId}`);
console.log(userItem);
return {
statusCode: 200,
body: JSON.stringify(userItem),
};
};
Sau đó, trong serverless.yml
tệp,
getUser:
handler: user/get.getUserById
events:
- http:
path: /user/{id}
method: get
Liệt kê Người dùng
Khi chúng tôi viết trình xử lý để tạo người dùng, hãy nhớ rằng chúng tôi đã đẩy (LPUSH
) userId thành một users
danh sách.
Bây giờ, chúng ta phải lấy tất cả các id đó bằng lệnh LRANGE
.
Lưu ý:LRANGE không hiệu quả lắm nếu danh sách các bài đăng bắt đầu quá lớn và chúng tôi muốn truy cập các phần tử ở giữa danh sách, vì Redis Lists được hỗ trợ bởi các danh sách được liên kết. Nếu một hệ thống được thiết kế để phân loại sâu hàng triệu mục, tốt hơn nên sử dụng các Bộ được sắp xếp để thay thế.
Sau khi nhận được tất cả userId, chúng ta có thể lặp lại từng id
và nhận thông tin hồ sơ người dùng bằng HGETALL
.
Hãy xem điều này trông như thế nào trong mã.
"use strict";
var Redis = require("ioredis");
if (typeof client === "undefined") {
var client = new Redis(process.env.REDIS_CLIENT);
}
module.exports.getAllUsers = async (event) => {
let users = [];
let response = await client.lrange("users", 0, -1);
async function getAllUsers() {
let users = [];
await Promise.all(
response.map(async (userId) => {
const item = await client.hgetall(`userItem:${userId}`);
users.push(item);
console.log(users);
})
);
return users;
}
users = await getAllUsers();
return {
statusCode: 200,
body: JSON.stringify(users),
};
};
Sau đó, đối với serverless.yml
listUsers:
handler: user/list.getAllUsers
events:
- http:
path: /users
method: get
Và đó là nó dành cho người dùng users
điểm cuối. Bạn có thể tiếp tục và triển khai ứng dụng của mình, nếu bạn chưa làm điều đó.
sls deploy
Đăng
Sau khi người dùng tạo tài khoản, họ sẽ được phép
- Tạo một bài đăng
- Nhận một bài đăng theo Id
- Nhận danh sách các bài đăng của họ
- Thích hoặc không thích một bài đăng (Phản ứng lại bài đăng)
Hãy bắt đầu.
Tạo bài đăng
Các thông số cần thiết để tạo một bài đăng là
- userId
- postId (Tự động tạo bởi UUID)
- postText
- postImage
- createdOn
Có 3 bước.
- Sử dụng lệnh HMSET để đặt chi tiết bài đăng thành Khóa băm
postItem:${postId}
. - Sử dụng lệnh LPUSH để thêm postId vào danh sách
posts
. - Sử dụng lệnh LPUSH để thêm postId vào danh sách
userPost:${userId}
.
Chúng tôi sẽ sử dụng một đường dẫn để thực hiện nhiệm vụ này theo thứ tự thời gian.
Tạo một tệp trong post
thư mục có tên create.js
và thêm mã sau vào nó.
"use strict";
const uuid = require("uuid");
var Redis = require("ioredis");
if (typeof client === "undefined") {
var client = new Redis(process.env.REDIS_CLIENT);
}
/**
*
* @param {userId,postId,postText,postImage,createdOn} event
* @returns
*/
module.exports.createPost = async (event) => {
const timestamp = new Date().getTime();
const postId = uuid.v1();
const data = JSON.parse(event.body);
if (data == null) {
return {
statusCode: 400,
body: JSON.stringify(
{
message: "Couldn't create the Post item",
},
null,
2
),
};
}
console.log(`postId is ${postId}`);
client.pipeline(
await client.hmset(
`postItem:${postId}`,
"id",
postId,
"userId",
data.userId,
"postText",
data.postText,
"postImage",
data.postImage,
"createdOn",
timestamp
),
await client.lpush("posts", postId),
await client.lpush(`userPost:${data.userId}`, postId)
);
//get and display saved post item
const postItem = await client.hgetall(`postItem:${postId}`);
console.log(postItem);
return {
statusCode: 200,
body: JSON.stringify(postItem),
};
};
Sau đó, dưới các hàm trong serverless.yml
, thêm
createPost:
handler: post/create.createPost
events:
- http:
path: /post
method: post
Triển khai và thử nghiệm.
Nhận bài đăng theo Id
Khi nhận được bài đăng bằng Id, chúng tôi muốn lấy và đính kèm thông tin chi tiết của quản trị viên bài đăng, cùng với số lượt phản ứng (thích) bài đăng đã có cho đến nay.
Tôi biết rằng chúng tôi chưa xem xét việc thích hay không thích một bài đăng nào, chỉ cần đợi ở đó, chúng tôi sẽ hoàn thành nó. Tạo một tệp có tên get.js
trong thư mục bài đăng và lưu cái này
"use strict";
var Redis = require("ioredis");
if (typeof client === "undefined") {
var client = new Redis(process.env.REDIS_CLIENT);
}
module.exports.getPostById = async (event) => {
const postId = event.pathParameters.id;
if (postId == null) {
return {
statusCode: 400,
body: JSON.stringify(
{
message: "Couldn't get the post item",
},
null,
2
),
};
}
console.log(`postId is ${postId}`);
//get and display saved post item
const postItem = await client.hgetall(`postItem:${postId}`);
const userItem = await client.hgetall(`userItem:${postItem.userId}`);
const postReactionsCount = await client.get(`postReactionsCount:${postId}`);
postItem["postAdmin"] = userItem;
postItem["reactionCount"] =
postReactionsCount == null ? 0 : postReactionsCount;
console.log(postItem);
console.log(userItem);
return {
statusCode: 200,
body: JSON.stringify(postItem),
};
};
Từ đoạn mã trên, trước tiên, chúng tôi nhận được tất cả các chi tiết về bài đăng cho một bài đăng cụ thể bằng cách sử dụng hgetall
và khóa postItem:${postId}
.
Sau đó, vì đối tượng bài đăng có userId của người dùng tạo bài đăng (quản trị viên bài đăng), chúng tôi sử dụng userItem:${postItem.userId}
để lấy chi tiết người dùng cho người dùng đó.
Hãy nhớ rằng đây là khóa chính xác mà chúng tôi đã sử dụng trong điểm cuối tạo người dùng ở trên.
Thứ ba, chúng tôi nhận được postReactionCount bằng cách sử dụng get
lệnh và một khóa postReactionsCount:${postId}
mà chúng tôi sẽ sử dụng sau này để lưu postReactionsCount.
Triển khai và thử nghiệm
Phản hồi bài đăng
Đây là điểm cuối thú vị nhất của toàn bộ ứng dụng. Thật là vui khi viết.
Người dùng được phép thích hoặc không thích một bài đăng. Bây giờ, khi người dùng nhấp vào nút thích, trước tiên, chúng tôi kiểm tra xem người dùng này đã thích bài đăng trước đó chưa.
Nếu có, chúng tôi, không giống như bài đăng. Khác, chúng tôi thích bài đăng.
Bạn có hiểu không?
Cũng giống như Instagram hoặc twitter.
Tạo một tệp trong thư mục bài đăng có tên react_to_post.js
Điểm cuối lấy userId
và postId
dưới dạng tham số đường dẫn.
Hãy xem một lệnh mới. Tập hợp đã được sắp xếp. Chúng tôi sẽ sử dụng một tập hợp được sắp xếp để thêm userId của người dùng thích bài đăng và dấu thời gian khi họ thích bài đăng.
zadd(`postReactions:${postId}`, timestamp, data.userId)
Chìa khóa là postReactions:${postId}
.
Các nhóm được sắp xếp bắt đầu bằng Z. Từ tài liệu Redis, zadd
Thêm tất cả các thành viên được chỉ định với điểm số được chỉ định vào tập hợp đã sắp xếp được lưu trữ tại khóa. Có thể chỉ định nhiều cặp điểm / thành viên. Nếu một thành viên được chỉ định đã là thành viên của tập hợp được sắp xếp, điểm số sẽ được cập nhật và phần tử được lắp lại vào đúng vị trí để đảm bảo thứ tự chính xác.
Bước tiếp theo là tăng postReactionsCount:${postId} using the
lệnh incr`.
Hãy nhớ rằng chúng tôi đã sử dụng khóa ở trên trong điểm cuối nhận Bài đăng theo Id để nhận số lượng phản ứng sau.
incr(`postReactionsCount:${postId}`),
Cuối cùng, chúng tôi lưu chi tiết phản ứng bài đăng của người dùng vào Hash
hmset(`userPostReactions:${data.userId}`,
"postId", postId,
"userId", data.userId,
"timestamp", timestamp
),
Dựa trên tất cả những điều này, đây là các mẫu truy cập có sẵn.
- Chúng tôi có thể nhận được số lượng phản ứng bài đăng.
- Chúng tôi có thể thu hút tất cả người dùng đã phản ứng với một bài đăng, theo thứ tự tăng dần hoặc giảm dần
- Chúng tôi có thể xem tất cả các bài đăng mà người dùng đã phản hồi.
Chúng tôi đã đề cập trước đó rằng, chúng tôi cần thực hiện kiểm tra xem liệu trước đó người dùng có thích một bài đăng hay không. Nếu có, chúng tôi không giống như bài đăng đó. Khác, chúng tôi thích bài đăng
Chúng tôi sẽ sử dụng zscore
lệnh cho việc này.
Trả về điểm của thành viên trong tập hợp đã sắp xếp tại khóa. Nếu thành viên không tồn tại trong tập hợp đã sắp xếp hoặc khóa không tồn tại, thì trả về nil.
zscore(`postReactions:${postId}`, data.userId);
if zscore
là null, thì người dùng không thích nó. Khác, người dùng đã thích nó.
Đây là giao diện của mã hoàn chỉnh
"use strict";
const uuid = require("uuid");
var Redis = require("ioredis");
if (typeof client === "undefined") {
var client = new Redis(process.env.REDIS_CLIENT);
}
/**
*
* @param {userId,postId,postText,postImage,createdOn} event
* @returns
*/
module.exports.reactToPost = async (event) => {
const timestamp = new Date().getTime();
const data = JSON.parse(event.body);
const postId = event.pathParameters.id;
if (data == null || postId == null) {
return {
statusCode: 400,
body: JSON.stringify(
{
message: "Couldn't react to the Post",
},
null,
2
),
};
}
console.log(`postId is ${postId}`);
console.log(`userId is ${data.userId}`);
// first check if user has already liked the post
const hasUserReacted = await client.zscore(
`postReactions:${postId}`,
data.userId
);
if (hasUserReacted == null) {
//user hasn't reacted.
client.pipeline(
await client.incr(`postReactionsCount:${postId}`),
await client.zadd(`postReactions:${postId}`, timestamp, data.userId),
await client.hmset(
`userPostReactions:${data.userId}`,
"postId",
postId,
"userId",
data.userId,
"timestamp",
timestamp
)
);
} else {
//user already reacted, so unreact
client.pipeline(
await client.decr(`postReactionsCount:${postId}`),
await client.zrem(`postReactions:${postId}`, data.userId),
await client.hdel(
`userPostReactions:${data.userId}`,
"postId",
postId,
"userId",
data.userId,
"timestamp",
timestamp
)
);
}
//return the post reaction count
const postReactionsCount = await client.get(`postReactionsCount:${postId}`);
console.log(postReactionsCount);
return {
statusCode: 200,
body: JSON.stringify({
postReactionCount: parseInt(postReactionsCount),
}),
};
};
Sau đó, trong serverless.yml
reactToPosts:
handler: post/react_to_post.reactToPost
events:
- http:
path: /post/{id}/react
method: post
Triển khai và thử nghiệm.
Nhấn nút gửi trên trình kiểm tra API của bạn (tôi sử dụng PostMan) nhiều lần và xem cách "postReactionCount" chuyển đổi giữa 0 và 1.
Thay đổi UserId và kiểm tra lại.
Có rất nhiều mẫu truy cập và các bản sửa lỗi khác mà bạn có thể thêm vào API này.
Còn bạn thì sao, hãy chấp nhận thử thách để mở rộng điều này và tìm hiểu thêm.
Đây là liên kết đến mã nguồn hoàn chỉnh
Tôi hoàn toàn yêu thích đường cong học tập không quá dốc của Redis và thực tế là nó cho phép tôi lưu dữ liệu theo cách tôi truy xuất.
Luôn biết các kiểu truy cập của bạn trước khi bạn bắt đầu phát triển ứng dụng.
Tôi rất vui khi viết bài này, hy vọng bạn đã học được một hoặc hai điều.
Tôi đã làm sai ở đâu đó? Một siêu Sayan như bạn sẽ không ngần ngại cho tôi biết.
Trong bài viết tiếp theo, chúng tôi sẽ xây dựng một ứng dụng Flutter để sử dụng API này. Hãy theo dõi.
Chúc mừng đồng chí mã hóa✌🏿
Tham chiếu
- Upstash Docs
- Redis
- Rung động
- Tìm nạp dữ liệu từ internet