跳到主要内容

在云函数中操作文档型数据库

CloudBase 文档型数据库是一个灵活、可扩展的 NoSQL 数据库,支持 JSON 文档存储。在云函数中,您可以通过 Node.js SDK 或 HTTP API 来操作数据库,实现数据的增删改查、聚合查询等功能。

数据库概述

核心概念

  • 集合(Collection):类似于关系型数据库中的表,用于存储文档
  • 文档(Document):数据库中的基本存储单元,采用 JSON 格式
  • 数据模型(Data Model):结构化的数据定义,提供类型安全和数据验证
  • 索引(Index):提高查询性能的数据结构

技术优势

  • 灵活性:无需预定义表结构,支持动态字段
  • 扩展性:自动扩缩容,支持海量数据存储
  • 一致性:支持 ACID 事务,保证数据一致性
  • 实时性:支持实时数据监听和同步

操作方式概览

集合操作

集合操作提供了直接、灵活的数据库访问方式,适用于快速开发和原型验证。

初始化数据库

const tcb = require('@cloudbase/node-sdk');

exports.main = async (event, context) => {
// 初始化 CloudBase
const app = tcb.init({
env: tcb.SYMBOL_CURRENT_ENV // 使用当前环境
});

// 获取数据库实例
const db = app.database();
const _ = db.command; // 获取查询指令

// 您的业务逻辑
return { success: true };
};

数据查询

const tcb = require('@cloudbase/node-sdk');

exports.main = async (event, context) => {
const app = tcb.init({ env: tcb.SYMBOL_CURRENT_ENV });
const db = app.database();

try {
// 根据文档 ID 查询单条记录
const result = await db.collection('users')
.doc(event.userId)
.get();

if (result.data.length === 0) {
return {
success: false,
error: '用户不存在'
};
}

const user = result.data[0];

return {
success: true,
user: {
id: user._id,
name: user.name,
email: user.email,
createdAt: user.createdAt
}
};
} catch (error) {
console.error('查询用户失败:', error);
return {
success: false,
error: error.message
};
}
};

数据操作

const tcb = require('@cloudbase/node-sdk');

exports.main = async (event, context) => {
const app = tcb.init({ env: tcb.SYMBOL_CURRENT_ENV });
const db = app.database();

try {
// 创建单条记录
const newUser = {
name: event.name,
email: event.email,
phone: event.phone,
status: 'active',
createdAt: new Date(),
updatedAt: new Date(),
profile: {
avatar: event.avatar || '',
bio: event.bio || '',
preferences: {
language: 'zh-CN',
timezone: 'Asia/Shanghai'
}
}
};

const result = await db.collection('users').add(newUser);

return {
success: true,
userId: result.id,
message: '用户创建成功'
};
} catch (error) {
console.error('创建用户失败:', error);
return {
success: false,
error: error.message
};
}
};

数据模型操作

数据模型提供了结构化的数据访问方式,支持类型验证、字段约束和关联查询。

初始化数据模型

const tcb = require('@cloudbase/node-sdk');

exports.main = async (event, context) => {
const app = tcb.init({ env: tcb.SYMBOL_CURRENT_ENV });

// 获取数据模型实例
const models = app.models;

// 访问具体的数据模型
const userModel = models.user;
const orderModel = models.order;
const productModel = models.product;

// 您的业务逻辑
return { success: true };
};

数据模型查询

const tcb = require('@cloudbase/node-sdk');

exports.main = async (event, context) => {
const app = tcb.init({ env: tcb.SYMBOL_CURRENT_ENV });
const models = app.models;

try {
// 查询单条用户记录
const result = await models.user.get({
filter: {
where: {
_id: {
$eq: event.userId
}
}
},
select: {
$master: true // 返回所有字段
}
});

if (result.data.records.length === 0) {
return {
success: false,
error: '用户不存在'
};
}

const user = result.data.records[0];

return {
success: true,
user: user
};
} catch (error) {
console.error('查询用户失败:', error);
return {
success: false,
error: error.message
};
}
};

数据模型操作

const tcb = require('@cloudbase/node-sdk');

exports.main = async (event, context) => {
const app = tcb.init({ env: tcb.SYMBOL_CURRENT_ENV });
const models = app.models;

try {
// 创建新订单
const orderData = {
orderNumber: `ORD${Date.now()}`,
userId: event.userId,
items: event.items,
totalAmount: event.totalAmount,
shippingAddress: event.shippingAddress,
status: 'pending',
paymentMethod: event.paymentMethod,
notes: event.notes || ''
};

const result = await models.order.create({
data: orderData
});

return {
success: true,
orderId: result.data._id,
orderNumber: orderData.orderNumber,
message: '订单创建成功'
};
} catch (error) {
console.error('创建订单失败:', error);
return {
success: false,
error: error.message
};
}
};

高级功能

事务处理

const tcb = require('@cloudbase/node-sdk');

exports.main = async (event, context) => {
const app = tcb.init({ env: tcb.SYMBOL_CURRENT_ENV });
const db = app.database();

try {
// 开始事务
const transaction = await db.startTransaction();

try {
const { fromUserId, toUserId, amount } = event;

// 1. 检查转出用户余额
const fromUserResult = await transaction.collection('users')
.doc(fromUserId)
.get();

if (fromUserResult.data[0].balance < amount) {
throw new Error('余额不足');
}

// 2. 扣除转出用户余额
await transaction.collection('users')
.doc(fromUserId)
.update({
balance: db.command.inc(-amount),
updatedAt: new Date()
});

// 3. 增加转入用户余额
await transaction.collection('users')
.doc(toUserId)
.update({
balance: db.command.inc(amount),
updatedAt: new Date()
});

// 4. 记录转账日志
await transaction.collection('transactions').add({
fromUserId,
toUserId,
amount,
type: 'transfer',
status: 'completed',
createdAt: new Date()
});

// 提交事务
await transaction.commit();

return {
success: true,
message: '转账成功'
};
} catch (error) {
// 回滚事务
await transaction.rollback();
throw error;
}
} catch (error) {
console.error('转账失败:', error);
return {
success: false,
error: error.message
};
}
};

聚合查询

const tcb = require('@cloudbase/node-sdk');

exports.main = async (event, context) => {
const app = tcb.init({ env: tcb.SYMBOL_CURRENT_ENV });
const db = app.database();

try {
// 销售数据统计
const salesStats = await db.collection('orders')
.aggregate()
.match({
status: 'completed',
createdAt: {
$gte: new Date(event.startDate),
$lte: new Date(event.endDate)
}
})
.group({
_id: {
year: { $year: '$createdAt' },
month: { $month: '$createdAt' },
day: { $dayOfMonth: '$createdAt' }
},
totalOrders: { $sum: 1 },
totalRevenue: { $sum: '$totalAmount' },
averageOrderValue: { $avg: '$totalAmount' },
maxOrderValue: { $max: '$totalAmount' },
minOrderValue: { $min: '$totalAmount' }
})
.sort({
'_id.year': 1,
'_id.month': 1,
'_id.day': 1
})
.end();

// 产品销量统计
const productStats = await db.collection('orders')
.aggregate()
.match({
status: 'completed'
})
.unwind('$items')
.group({
_id: '$items.productId',
totalSold: { $sum: '$items.quantity' },
totalRevenue: { $sum: { $multiply: ['$items.quantity', '$items.price'] } },
orderCount: { $sum: 1 }
})
.lookup({
from: 'products',
localField: '_id',
foreignField: '_id',
as: 'product'
})
.unwind('$product')
.project({
productName: '$product.name',
category: '$product.category',
totalSold: 1,
totalRevenue: 1,
orderCount: 1,
averagePrice: { $divide: ['$totalRevenue', '$totalSold'] }
})
.sort({ totalRevenue: -1 })
.limit(10)
.end();

return {
success: true,
data: {
dailySales: salesStats.list,
topProducts: productStats.list
}
};
} catch (error) {
console.error('聚合查询失败:', error);
return {
success: false,
error: error.message
};
}
};

地理位置查询

const tcb = require('@cloudbase/node-sdk');

exports.main = async (event, context) => {
const app = tcb.init({ env: tcb.SYMBOL_CURRENT_ENV });
const db = app.database();
const _ = db.command;

try {
const { longitude, latitude, radius = 5000 } = event; // 默认 5 公里

// 查询附近的商店
const nearbyStores = await db.collection('stores')
.where({
location: _.geoNear({
geometry: new db.Geo.Point(longitude, latitude),
maxDistance: radius,
minDistance: 0
}),
status: 'active'
})
.field({
name: true,
address: true,
phone: true,
location: true,
businessHours: true,
services: true
})
.get();

// 计算距离并排序
const storesWithDistance = nearbyStores.data.map(store => {
const distance = calculateDistance(
latitude, longitude,
store.location.coordinates[1], store.location.coordinates[0]
);

return {
...store,
distance: Math.round(distance)
};
}).sort((a, b) => a.distance - b.distance);

// 查询指定区域内的配送范围
const deliveryArea = new db.Geo.Polygon([
new db.Geo.LineString([
new db.Geo.Point(longitude - 0.01, latitude - 0.01),
new db.Geo.Point(longitude + 0.01, latitude - 0.01),
new db.Geo.Point(longitude + 0.01, latitude + 0.01),
new db.Geo.Point(longitude - 0.01, latitude + 0.01),
new db.Geo.Point(longitude - 0.01, latitude - 0.01)
])
]);

const deliveryStores = await db.collection('stores')
.where({
deliveryArea: _.geoIntersects({
geometry: deliveryArea
}),
deliveryEnabled: true
})
.get();

return {
success: true,
data: {
nearbyStores: storesWithDistance,
deliveryAvailable: deliveryStores.data.length > 0,
deliveryStores: deliveryStores.data
}
};
} catch (error) {
console.error('地理位置查询失败:', error);
return {
success: false,
error: error.message
};
}
};

// 计算两点间距离(米)
function calculateDistance(lat1, lon1, lat2, lon2) {
const R = 6371e3; // 地球半径(米)
const φ1 = lat1 * Math.PI / 180;
const φ2 = lat2 * Math.PI / 180;
const Δφ = (lat2 - lat1) * Math.PI / 180;
const Δλ = (lon2 - lon1) * Math.PI / 180;

const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ/2) * Math.sin(Δλ/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

return R * c;
}

数据监听和实时同步

const tcb = require('@cloudbase/node-sdk');

exports.main = async (event, context) => {
const app = tcb.init({ env: tcb.SYMBOL_CURRENT_ENV });
const db = app.database();

try {
// 监听订单状态变化
const watcher = db.collection('orders')
.where({
userId: event.userId,
status: db.command.in(['pending', 'processing', 'shipped'])
})
.watch({
onChange: (snapshot) => {
console.log('订单状态变化:', snapshot);

// 处理变化的文档
snapshot.docChanges.forEach(change => {
const { doc, queueType } = change;

switch (queueType) {
case 'init':
console.log('初始化订单:', doc.data());
break;
case 'update':
console.log('订单更新:', doc.data());
// 发送状态更新通知
sendOrderStatusNotification(doc.data());
break;
case 'add':
console.log('新订单:', doc.data());
break;
case 'remove':
console.log('订单删除:', doc.data());
break;
}
});
},
onError: (error) => {
console.error('监听错误:', error);
}
});

// 在云函数结束前关闭监听
// watcher.close();

return {
success: true,
message: '订单监听已启动'
};
} catch (error) {
console.error('设置数据监听失败:', error);
return {
success: false,
error: error.message
};
}
};

async function sendOrderStatusNotification(order) {
// 发送订单状态更新通知的逻辑
console.log(`发送通知: 订单 ${order.orderNumber} 状态更新为 ${order.status}`);
}

性能优化建议

1. 索引优化

const tcb = require('@cloudbase/node-sdk');

exports.main = async (event, context) => {
const app = tcb.init({ env: tcb.SYMBOL_CURRENT_ENV });
const db = app.database();

try {
// 创建复合索引
await db.collection('orders').createIndex({
keys: {
userId: 1,
status: 1,
createdAt: -1
},
options: {
name: 'user_status_time_index',
background: true
}
});

// 创建地理位置索引
await db.collection('stores').createIndex({
keys: {
location: '2dsphere'
},
options: {
name: 'location_index'
}
});

// 创建文本搜索索引
await db.collection('products').createIndex({
keys: {
name: 'text',
description: 'text',
tags: 'text'
},
options: {
name: 'text_search_index',
weights: {
name: 10,
description: 5,
tags: 1
}
}
});

return {
success: true,
message: '索引创建成功'
};
} catch (error) {
console.error('创建索引失败:', error);
return {
success: false,
error: error.message
};
}
};

2. 查询优化

const tcb = require('@cloudbase/node-sdk');

exports.main = async (event, context) => {
const app = tcb.init({ env: tcb.SYMBOL_CURRENT_ENV });
const db = app.database();

try {
// 优化查询:使用投影减少数据传输
const result = await db.collection('orders')
.where({
userId: event.userId,
status: 'completed'
})
.field({
// 只返回需要的字段
orderNumber: true,
totalAmount: true,
createdAt: true,
// 排除大字段
items: false,
shippingAddress: false
})
.orderBy('createdAt', 'desc')
.limit(20)
.get();

// 使用聚合管道优化复杂查询
const stats = await db.collection('orders')
.aggregate()
.match({
userId: event.userId,
createdAt: {
$gte: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
}
})
.group({
_id: null,
totalOrders: { $sum: 1 },
totalAmount: { $sum: '$totalAmount' },
averageAmount: { $avg: '$totalAmount' }
})
.end();

return {
success: true,
orders: result.data,
statistics: stats.list[0] || {
totalOrders: 0,
totalAmount: 0,
averageAmount: 0
}
};
} catch (error) {
console.error('查询优化失败:', error);
return {
success: false,
error: error.message
};
}
};

3. 连接池管理

const tcb = require('@cloudbase/node-sdk');

// 全局初始化,复用连接
const app = tcb.init({ env: tcb.SYMBOL_CURRENT_ENV });
const db = app.database();

exports.main = async (event, context) => {
try {
// 使用全局数据库实例,避免重复初始化
const result = await db.collection('users')
.doc(event.userId)
.get();

return {
success: true,
user: result.data[0]
};
} catch (error) {
console.error('数据库操作失败:', error);
return {
success: false,
error: error.message
};
}
};

错误处理和调试

常见错误处理

const tcb = require('@cloudbase/node-sdk');

exports.main = async (event, context) => {
const app = tcb.init({ env: tcb.SYMBOL_CURRENT_ENV });
const db = app.database();

try {
const result = await db.collection('users')
.doc(event.userId)
.get();

return {
success: true,
user: result.data[0]
};
} catch (error) {
console.error('数据库操作失败:', {
error: error.message,
code: error.code,
requestId: error.requestId,
stack: error.stack
});

// 根据错误类型返回不同的响应
switch (error.code) {
case 'PERMISSION_DENIED':
return {
success: false,
error: '权限不足',
code: 'PERMISSION_DENIED'
};
case 'INVALID_PARAM':
return {
success: false,
error: '参数无效',
code: 'INVALID_PARAM'
};
case 'NETWORK_ERROR':
return {
success: false,
error: '网络连接失败,请稍后重试',
code: 'NETWORK_ERROR'
};
default:
return {
success: false,
error: '数据库操作失败',
code: error.code || 'UNKNOWN_ERROR'
};
}
}
};

相关文档