私の目標
Service Workersを介してオフラインで動作し、バックエンドなしで SQlite ファイルをクエリできるReact JS WEB APPを作成します。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>
それから...私はbetter-sqlite3のような別のsqliteサポートライブラリの検索に移りました
ベター-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 にロードすることは可能だと思いました。
だから私はこの質問をしました: 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 のオブジェクトまたはドキュメントがあります。これらの .json ファイルは 19 個あり、それぞれがテーブルを表しています。
AAAAND...クエリを実行するには、.json ファイル (テーブル) 間で変更する必要がありますが、ファイル変換後、_rev 属性がないため、bulkDocs を使用してレジストリを読み込むたびに、テーブル間で競合が発生します。 _rev 属性がありません。
これは私のdbサービスのコードです:
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 ファイルは load 関数と同じディレクトリにありましたが、データは読み込まれません。
だから私はbulkDocsバージョンに固執しています。
質問
非常に長い投稿で申し訳ありません。すべての文脈化の後、質問があります。
- React Web App 環境で sqliteライブラリをセットアップする可能性はありますか?
- バックエンドなしで?
- .json テーブルを切り替える推奨される方法は何ですか?
- 保存されている前のものを削除して、次のものをロードする必要がありますか?
- または、すべてのテーブルを手動でロードしてから、次を使用してダンプしますポーチダンプ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 を使用しているため、コンポーネントの状態で DB の参照を保存しています。
テーブル間で変更するたびに、bulkDocs を使用する関数を呼び出しているため、最適化が不足していると思います。テーブルが既に IndexedDB に挿入されているかどうかを確認する必要があるかもしれません。