You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 12:35:05