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

Posted

技术标签:

【中文标题】构建一个支持 React Web 应用程序和问题的 SQlite/PouchDB?【英文标题】:Building a SQlite/PouchDB supporting React Web App and questions? 【发布时间】:2019-07-23 15:32:44 【问题描述】:

我的目标


创建一个 React JS WEB APP,可以通过 Service Workers 离线工作,并且可以无需任何后端查询 SQlite 文件。我正在运行 Linux 操作系统。

问题


我在 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));

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

Kripken 的 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。

所以我问了这个问题:What is the correct way to load prebuilt SQlite databases with or without PouchDB in a React App

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

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

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

编辑 1:

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

AAAAND...我需要在 .json 文件(表)之间进行更改以进行查询,但是文件转换后,没有 _rev 属性,所以每次我使用 bulkDocs 加载注册表时,都会发生冲突表,因为它们缺少 _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;

文档示例:

表 1:

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

表 2:

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

在第一次 (dbLoad(Table1)) 调用中,所有文档都被加载,_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 版本。

问题

很抱歉发了很长的帖子,在进行了所有背景化之后,问题出现了:

是否有可能在 React Web App 环境? 并且没有任何后端? 在我的 .json 表之间切换的推荐方式是什么? 我应该删除存储的前一个并加载下一个吗? 或者手动加载每个表,然后使用pouch-dump-cli 转储它们?

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

感谢您的宝贵时间!

可能的答案


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

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 语句是表的名称并返回表文档,用于在 IndexedDB 上插入。对于每个 .json 文件,我正在创建一个新的数据库,然后进行查询,因为我正在使用 React,我正在将数据库的引用保存在组件状态上。

我认为缺少优化,因为每次我在表之间进行更改时,我都会调用使用 bulkDocs 的函数。也许我应该检查表是否已插入 IndexedDB。

【问题讨论】:

您做了两个相互矛盾的陈述:“然后我终于能够将 .json 数据导入 Pouch!真是如释重负!”,然后您说“接下来,让我们创建数据库并导入.json 文件中的数据。”您的代码示例似乎试图实现后者,但如果您“......终于能够将 .json 数据导入 Pouch!”,我无法理解您为什么需要该代码。 我已经编辑了问题 Martin,对于不清楚的部分,我深表歉意。 好的,但是我不明白您为什么创建代码来从 JSON 文件中导入数据。正如我在另一个问题中提到的,在博文Prebuilt databases with PouchDB 的第 2 部分中,有一个示例说明如何快速从 JSON 文件初始化 PouchDB。在您最近的更新之前,您似乎一直在说您成功地使用了它。你有吗? 哦,是的,我忘了提到,当您尝试使用 pouchdb-load 加载文件时,它会运行 JSON.parse 命令,该命令期望您的 JSON 是字符串,否则它失败了,尽管它是一个有效的 JSON 所以不可行? 这是 JSON.parse 抛出的错误:SyntaxError: "JSON.parse: unexpected character at line 1 column 2 of the JSON data",我花了一段时间才意识到这是一个错误对于 JSON 类型。你可以在这里查看:developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/… 【参考方案1】:

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

    如果您有 SQLite 文件,请转到我之前提出的问题:What is the correct way to load prebuilt SQlite databases with or without PouchDB in a React App

    搜索问题答案,然后执行 sqlite3 命令相应地输出 .json 文件。

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

    sqlite3 示例 ".output rslt.json" "SELECT ' \"id\": \"someTable' || SUBSTR(\"000000000\" || id, LENGTH(\"000000000\" || id) - 8, 9) || '\", \"anattr\": \"' || anattr || '\", \"anothe.rattr\": \"' || [anoth.erattr] || '\" ,' FROM some_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 语句是表的名称并返回表文档,用于在 IndexedDB 上插入。对于每个 .json 文件,我正在创建一个新的数据库,然后进行查询,因为我正在使用 React,我正在将数据库的引用保存在组件状态中。

我认为每次在表之间进行更改时,我都会调用使用 bulkDocs 的函数,因此缺乏优化。也许我应该检查表是否已插入 IndexedDB。

这将为每个 .json 文件创建一个 DATABASE !!!请记住,这不是最佳选择!我将为此努力优化方法。

感谢马丁的帮助!

【讨论】:

您可以通过 Sqlite 的字符串函数REPLACE() 确保您的 Sqlite 数据迁移查询始终导出纯净的 JSON,因此您将使用'\", \"anothe.rattr\": \"' || REPLACE([anoth.erattr], '"', '\"' || '\" 而不是'\", \"anothe.rattr\": \"' || [anoth.erattr] || '\"。 (免责声明:未经测试!您可能逃脱了某些引号,甚至可能逃脱了转义,)

以上是关于构建一个支持 React Web 应用程序和问题的 SQlite/PouchDB?的主要内容,如果未能解决你的问题,请参考以下文章

Ionic 框架宣布 2019 年将正式支持 Vue 和 React

React Native iOS 构建失败“无法执行命令:分段错误:11”

Ionic在2019年将支持Vue和React

我们可以使用 React 为 Android 和 Web 构建软件吗? [关闭]

如何使用 grpc-web 构建 react-redux 应用程序?

react js web代码可以用于使用react native构建移动应用程序吗?