构建一个支持 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”
我们可以使用 React 为 Android 和 Web 构建软件吗? [关闭]