如何为Ionic+Angular+Capacitor项目配置SQLite数据库
Ionic+Angular+Capacitor 配置SQLite并适配MongoDB后端完整指南
一、MongoDB到SQLite的适配思路
MongoDB的文档结构(比如聊天记录{_id: xxx, sender: xxx, content: xxx, chatRoomId: xxx, createdAt: xxx})转SQLite关系表的核心是扁平化文档结构:
- 简单场景(如单一聊天记录):直接将MongoDB文档字段映射为SQLite表列,MongoDB的
_id存为SQLite的TEXT类型,createdAt可转成时间戳(INTEGER)或ISO字符串(TEXT)存储 - 关联场景(含用户、聊天室):拆分为用户表、聊天室表、聊天记录表,用外键建立关联,遵循常规关系型数据库设计逻辑
同步逻辑核心:拉取后端数据时转成SQLite行数据;离线操作的本地数据,标记状态后待联网同步回MongoDB。
二、完整配置步骤
1. 安装Capacitor SQLite依赖
在Angular项目根目录执行命令:
npm install @capacitor-community/sqlite npx cap sync
2. 初始化SQLite数据库
创建sqlite.service.ts服务封装数据库操作:
import { Injectable } from '@angular/core'; import { CapacitorSQLite, SQLiteDBConnection, SQLiteConnection } from '@capacitor-community/sqlite'; @Injectable({ providedIn: 'root' }) export class SqliteService { private sqliteConnection: SQLiteConnection; private db: SQLiteDBConnection | null = null; constructor() { this.sqliteConnection = new SQLiteConnection(CapacitorSQLite); } async initDb(): Promise<void> { // 创建/打开本地数据库 this.db = await this.sqliteConnection.createConnection( 'chatAppDb', false, 'no-encryption', 1 ); await this.db.open(); // 创建聊天记录表 await this.db.execute(` CREATE TABLE IF NOT EXISTS chat_messages ( id TEXT PRIMARY KEY, sender_id TEXT NOT NULL, sender_name TEXT NOT NULL, content TEXT NOT NULL, chat_room_id TEXT NOT NULL, created_at INTEGER NOT NULL, is_sent BOOLEAN DEFAULT 0 ); `); // 可选:创建聊天室表 await this.db.execute(` CREATE TABLE IF NOT EXISTS chat_rooms ( id TEXT PRIMARY KEY, name TEXT NOT NULL, last_message TEXT, updated_at INTEGER ); `); } }
在app.component.ts的ngOnInit中初始化数据库:
async ngOnInit() { await this.sqliteService.initDb(); }
3. 实现MongoDB数据到SQLite的转换与存储
假设从MongoDB后端获取的聊天记录格式为:
interface MongoChatMessage { _id: string; sender: { _id: string; name: string }; content: string; chatRoomId: string; createdAt: string; // ISO格式字符串 }
在sqlite.service.ts中添加转换存储方法:
async saveMessagesFromMongo(messages: MongoChatMessage[]): Promise<void> { if (!this.db) return; // 批量转换Mongo文档为SQLite行数据 const batchData = messages.map(msg => ({ id: msg._id, sender_id: msg.sender._id, sender_name: msg.sender.name, content: msg.content, chat_room_id: msg.chatRoomId, created_at: new Date(msg.createdAt).getTime(), is_sent: 1 })); // 事务批量插入,避免重复操作 await this.db.run('BEGIN TRANSACTION'); for (const item of batchData) { const exists = await this.db.query('SELECT id FROM chat_messages WHERE id = ?', [item.id]); if (exists.values.length === 0) { await this.db.execute(` INSERT INTO chat_messages (id, sender_id, sender_name, content, chat_room_id, created_at, is_sent) VALUES (?, ?, ?, ?, ?, ?, ?) `, [item.id, item.sender_id, item.sender_name, item.content, item.chat_room_id, item.created_at, item.is_sent]); } } await this.db.run('COMMIT'); }
在API服务中调用该方法完成同步:
async fetchChatHistory(roomId: string) { const response = await this.http.get<MongoChatMessage[]>(`/api/chat/${roomId}`).toPromise(); await this.sqliteService.saveMessagesFromMongo(response); return response; }
4. 离线数据读取与本地操作
在sqlite.service.ts中添加本地数据读取方法:
async getLocalChatMessages(roomId: string): Promise<any[]> { if (!this.db) return []; const result = await this.db.query(` SELECT * FROM chat_messages WHERE chat_room_id = ? ORDER BY created_at ASC `, [roomId]); // 转换为前端适配的格式(对齐MongoDB返回结构) return result.values.map(row => ({ _id: row.id, sender: { _id: row.sender_id, name: row.sender_name }, content: row.content, chatRoomId: row.chat_room_id, createdAt: new Date(row.created_at).toISOString(), isSent: row.is_sent === 1 })); }
离线时直接调用该方法获取本地记录;联网时可优先加载本地数据,再同步后端最新内容。
5. 离线消息同步逻辑
离线发送消息时先存本地,标记未发送状态,联网后同步到后端:
// 存本地未发送消息 async saveLocalMessage(message: Omit<MongoChatMessage, '_id' | 'createdAt'>): Promise<string> { if (!this.db) return ''; const localId = `local_${Date.now()}`; // 生成临时ID const createdAt = Date.now(); await this.db.execute(` INSERT INTO chat_messages (id, sender_id, sender_name, content, chat_room_id, created_at, is_sent) VALUES (?, ?, ?, ?, ?, ?, ?) `, [localId, message.sender._id, message.sender.name, message.content, message.chatRoomId, createdAt, 0]); return localId; } // 同步未发送消息到后端 async syncUnsentMessages(): Promise<void> { if (!this.db) return; const unsent = await this.db.query('SELECT * FROM chat_messages WHERE is_sent = 0'); for (const msg of unsent.values) { try { const response = await this.http.post('/api/chat', { sender: { _id: msg.sender_id, name: msg.sender_name }, content: msg.content, chatRoomId: msg.chat_room_id, createdAt: new Date(msg.created_at).toISOString() }).toPromise(); // 同步成功后更新本地记录的ID和状态 await this.db.execute(` UPDATE chat_messages SET id = ?, is_sent = 1 WHERE id = ? `, [response._id, msg.id]); } catch (err) { console.error('同步消息失败:', err); continue; } } }
监听网络状态,联网时触发同步:
import { Network } from '@capacitor/network'; // 在app.component.ts的ngOnInit中添加 Network.addListener('networkStatusChange', status => { if (status.connected) { this.sqliteService.syncUnsentMessages(); } });
三、注意事项
- 字段映射保持一致:MongoDB的
_id对应SQLite的id,日期类型统一处理为时间戳或ISO字符串 - 避免重复数据:拉取后端数据时通过ID判断是否已存在,防止重复插入
- 事务优化:批量操作使用事务,提升性能和数据一致性
- 状态监听:用Capacitor Network插件准确判断在线/离线状态,触发同步逻辑
内容的提问来源于stack exchange,提问作者Mahima
相关产品推荐
相关产品推荐

