构建一个 SQlite/PouchDB 支持 React Web 应用程序和问题?

Building a SQlite/PouchDB supporting React Web App and questions?

我的目标


创建一个 React JS WEB APP 可以通过 Service Workers 离线工作并且可以查询 SQlite 文件 任何后端。我是 运行 Linux OS.

问题


我正在为 React Js Web 应用程序上的 SQlite 使用而苦苦挣扎。我正在使用 create-react-app 并尝试查询 SQlite 数据库。

从 sqlite3 开始

我不能完全将 sqlite3 安装为 npm 包,因为它需要一个名为 aws-sdk 的依赖项,安装此包后,它会输出以下内容:

/node_modules/sqlite3/node_modules/node-pre-gyp/lib/util/compile.js
Module not found: Can't resolve 'npm' in '/home/user/Documents/snv3/node_modules/sqlite3/node_modules/node-pre-gyp/lib/util'

./node_modules/sqlite3/node_modules/node-pre-gyp/lib/util/nw-pre-gyp/index.html 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
> <!doctype html>
| <html>
| <head>

然后...我继续寻找另一个 sqlite 支持库,例如 better-sqlite3

Better-Sqlite3

导入 better-sqlite3 后,这是我浏览器屏幕上的输出:

TypeError: Class is undefined
exports.wrap
node_modules/babel-loader/lib/index.js??ref--6-oneOf-2!/home/user/Documents/projectFolder/node_modules/better-sqlite3/lib/util.js:14

  11 | };
  12 | 
  13 | exports.wrap = function (Class, methodName, wrapper) {
> 14 |   var originalMethod = Class.prototype[methodName];
  15 | 
  16 |   if (typeof originalMethod !== 'function') {
  17 |     throw new TypeError("Missing method ".concat(methodName));

我不知道那是什么意思。库的故障排除部分没有任何内容,因此无法调试。

克里普肯 Sql.js

让我们尝试一些内置的 Javascript 和轻量级的东西。

哦不,我的内存堆刚刚在编译时爆炸了:

Starting the development server...


<--- Last few GCs --->
tart of marking 2696 ms) (average mu = 0.196, current mu = 0.078) alloca[19981:0x317f660]    30702 ms: Mark-sweep 1387.3 (1425.7) -> 1382.8 (1424.7) MB, 2779.6 / 0.0 ms  (+ 0.1 msin 91 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 2806 ms) (average mu = 0.104, current mu = 0.010) allocati[19981:0x317f660]    33503 ms: Mark-sweep 1386.7 (1424.7) -> 1385.2 (1425.7) MB, 2780.3 / 0.0 ms  (average mu = 0.056, current mu = 0.007) allocation failure scavenge might not succeed


<--- JS stacktrace --->

==== JS stack trace =========================================

    0: ExitFrame [pc: 0x30bcb58041bd]
Security context: 0x346742d1e789 <JSObject>
    1: get [0x146f266b8549] [/home/user/Documents/projectFolder/node_modules/@babel/traverse/lib/path/index.js:~99] [pc=0x30bcb6347fd5](this=0x2c6f95aa7759 <JSFunction NodePath (sfi =0x3a532511d061)>,/* anonymous */=0xb1cce8a8af9 <Object map = 0x3450d4054639>)
    2: /* anonymous */(aka /* anonymous */) [0xb1cce8a8899] [/home/user/Documents/projectFolder/node_modul...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 0x8b8210 node::Abort() [/usr/local/bin/node]
 2: 0x8b825c  [/usr/local/bin/node]
 3: 0xac1d1e v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]
 4: 0xac1f38 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]
 5: 0xeb11f2  [/usr/local/bin/node]
 6: 0xebd14a v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/usr/local/bin/node]
 7: 0xebdab4 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/usr/local/bin/node]
 8: 0xec03e5 v8::internal::Heap::AllocateRawWithRetry(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [/usr/local/bin/node]
 9: 0xe888c4 v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationSpace) [/usr/local/bin/node]
10: 0x112a2ae v8::internal::Runtime_AllocateInNewSpace(int, v8::internal::Object**, v8::internal::Isolate*) [/usr/local/bin/node]
11: 0x30bcb58041bd
Aborted (core dumped)

好吧,忘记 sqlite 库,让我们试试 PouchDB!

当前解决方案


PouchDB

所以,在这一切混乱之后,我放弃了使用 SQlite 库并尝试了一些离线优先友好的东西:Pouch DB。我认为可以将 SQlite 文件加载到 Pouch。

所以我问了这个问题:

不,它是一个 noSQL 数据库,不可能...

然后我不得不将我所有的 SQlite 数据库转换为 .json 文件,全部手动完成...

接下来,让我们创建数据库并从 .json 文件中导入数据。

编辑 1:

我的 SQlite 文件每个都有接近 5k 个注册表 table。 因此,我从 SQlite table 转换而来的每个 .json 文件都有 5k 个对象或文档,如您所愿。其中有 19 个 .json 文件,每个文件代表一个 table.

AAAAND...我需要在 .json 文件 (tables) 之间切换以进行查询,但文件转换后,没有 _rev 属性,所以每次我使用 bulkDocs 加载注册表,table 之间发生冲突,因为它们缺少 _rev 属性。

这是我的数据库服务的代码:

import PouchDB from 'pouchdb';
import PDBFind from 'pouchdb-find';
import PDBSilverLining from 'pouchdb-silverlining';
import TableEnumerator from '../utils/tableEnumerator';

import {
    Example_Table_Name
} from '../../db'

PouchDB.plugin(PDBFind);
PouchDB.plugin(PDBSilverLining);

class DbService {
    constructor() {
        this._db = new PouchDB('database');
    }

    static async dbLoad (table) {
        const dbInstance = new DbService()._db

        try {
            const respose = await dbInstance.bulkDocs(TableEnumerator(table))
        } catch(e) {
            console.error(e)
        }
    }

    static query(query) {
        const dbInstance = new DbService()._db

        return dbInstance.sql(query)
    }
}

export default DbService;

文档示例:

Table 1:

{ "_id": "table1_010101012",
    "Procedure": "XXXXX",
    "field4": "",
    "field5": "2B",
    *insert here some more irrelevant data* }

Table 2:

{ "_id": "table2_0555444777",
    "Procedure": "YYYYYYYYYYY",
    "field4": "",
    "field5": "2B",
    *insert here some more irrelevant data* }

在第一个 (dbLoad(Table1)) 调用中,加载所有文档并在第一个 table.

中创建 _rev 属性

当我使用 Table2.json 进行另一个调用 (dbLoad(Table2)) 时,它们会发生冲突,因为新文件缺少 _rev 属性,而当 Pouch 创建此属性时,他们是一样的!

编辑 2:

我尝试将我的代码修改为:

import PDBLoad from 'pouchdb-load';

PouchDB.plugin(PDBLoad);

static async dbLoad (table) {
        const db = new PouchDB(table);

        try {
            db.get('_local/preloaded').then(function (doc) {
            }).catch(function (err) {
              if (err.name !== 'not_found') {
                throw err;
              }
              // we got a 404, so the local docuent doesn't exist. so let's preload!
              return db.load('table_name.json').then(function () {
                // create the local document to note that we've preloaded
                return db.put({_id: '_local/preloaded'});
              });
            }).then(function () {
                console.log({include_docs: true})
              return db.allDocs({include_docs: true});
            })

        } catch(e) {
            console.error(e)
        }
    }

.json 文件与加载函数位于同一目录中,但它不加载数据。

所以我坚持使用 bulkDocs 版本。

问题

很抱歉拖了这么久post,语境化之后,问题来了:

我希望一切都得到很好的解释,我很乐意澄清您可能有的任何问题。

感谢您的宝贵时间!

可能的答案


好的,所以我能够通过创建这样的代码来解决我的问题。

import PouchDB from 'pouchdb';
import PDBFind from 'pouchdb-find';
import PDBSilverLining from 'pouchdb-silverlining';
import TableEnumerator from '../utils/tableEnumerator';

PouchDB.plugin(PDBFind);
PouchDB.plugin(PDBSilverLining);

class DbService {
    static async dbLoad (table) {
        const db = new PouchDB(table);

        try {
            await db.bulkDocs(TableEnumerator(table))
        } catch(e) {
            console.error(e)
        }

        return db
    }

    static async query(query, dbReference) {
        return dbReference.sql(query)
    }
}

export default DbService;

其中 switch 语句是 table 和 returns table 文档的名称,用于在 IndexedDB 上插入。对于每个 .json 文件,我都在创建一个新的数据库,然后在使用 React 时进行查询,我在组件状态上保存数据库的引用。

我认为缺少优化,因为每次我在 table 之间切换时,我都在调用使用 bulkDocs 的函数。也许我应该检查 table 是否已经插入到 IndexedDB 中。

对于未来的读者,这是解决问题的方法。

  1. 如果您有 SQLite 文件,请转到我之前提出的问题:
  2. 搜索问题答案,并相应地执行 sqlite3 命令输出 .json 文件。

  3. 当发出命令 SELECT 时,如果您有任何包含特殊字符的列,例如空白 space 或名称中的点,请在列名称上使用方球拍运算符[ ]:

    sqlite3 示例 ".output rslt.json" "SELECT '{ \"id\": \"someTable' || SUBSTR(\"000000000\" || id, 长度(\"000000000\" || id) - 8, 9) || '\", \"anattr\": \"' || anattr || '\", \"anothe.rattr\": \"' || [anoth.erattr] || '\" },' FROM some_table;";

  4. 我遇到了一个问题,有些 table 行有这样的双引号:"Attr": "Lorem ipsum "dolor" ”。这会导致解析错误。要修复它,请在引号前使用转义字符运算符 \:"Lorem ipsum \"dolor\" "。那应该修复双引号。

    您可以轻松地使用正则表达式来匹配此事件:\"dolor\",这将在双引号中找到您想要的单词。为了快速替换写入 \"dolor\" 并替换所有出现的地方,就在这样做之前检查您正在修改哪些文件!!!!

由于没有人对此表现出任何表现,我在上次更新中回答了我自己的问题:

好的,所以我能够通过创建这样的代码来解决我的问题。

import PouchDB from 'pouchdb';
import PDBFind from 'pouchdb-find';
import PDBSilverLining from 'pouchdb-silverlining';
import TableEnumerator from '../utils/tableEnumerator';

PouchDB.plugin(PDBFind);
PouchDB.plugin(PDBSilverLining);

class DbService {
    static async dbLoad (table) {
        const db = new PouchDB(table);

        try {
            await db.bulkDocs(TableEnumerator(table))
        } catch(e) {
            console.error(e)
        }

        return db
    }

    static async query(query, dbReference) {
        return dbReference.sql(query)
    }
}

export default DbService;

其中 switch 语句是 table 和 returns table 文档的名称,用于在 IndexedDB 上插入。对于每个 .json 文件,我正在创建一个新的数据库,然后进行查询,因为我使用的是 React,我在组件状态上保存数据库的引用。

我认为缺少优化,因为每次我在 table 之间切换时,我都在调用使用 bulkDocs 的函数。也许我应该检查 table 是否已经插入到 IndexedDB 中。

这会为每个 .json 文件创建一个 DATABASE!请记住,这不是最优的!我将为此研究优化方法。

感谢并感谢 Martin 的帮助!