1

私の目標


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 に挿入されているかどうかを確認する必要があるかもしれません。

4

1 に答える 1