Создание SQlite/PouchDB с поддержкой React Web App и вопросы?

Моя цель


Создайте React JS ВЕБ-ПРИЛОЖЕНИЕ, который может работать в автономном режиме через Сервисные работники и может запрашивать файл SQlite без какого-либо бэкэнда. Я использую ОС Linux.

Проблема


Я борюсь с использованием SQlite в веб-приложении React Js. Я использую создать-реагировать-приложение и пытаюсь запросить базу данных 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, такой как лучше-sqlite3.

Лучше-Sqlite3

Когда лучше-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!

Текущее решение


МешокДБ

Итак, после всего этого беспорядка я отказался от использования библиотек SQlite и попытался сделать что-то, что было в первую очередь удобно в автономном режиме: Pouch DB. Я думал, что можно загрузить файл SQlite в Pouch.

Итак, я задал этот вопрос: Как правильно загружать готовые базы данных SQlite с PouchDB или без него в приложении React

Нет, это база данных noSQL, это невозможно...

Затем мне пришлось преобразовать всю мою базу данных SQlite в файлы .json, я сделал все это вручную...

Далее давайте создадим базу данных и импортируем данные из файлов .json.

Редактировать 1:

В моем файле SQlite есть что-то близкое к 5k реестров в каждой таблице. Таким образом, каждый файл .json, который я преобразовал из таблицы SQlite, содержит 5 тыс. объектов или документов по вашему усмотрению. И таких файлов .json 19, каждый из которых представляет собой таблицу.

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.

Когда я делаю другой вызов (dbLoad(Table2)), используя Table2.json, они конфликтуют, потому что в новом файле отсутствует атрибут _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.info({include_docs: true})
              return db.allDocs({include_docs: true});
            })

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

Файл .json находился в том же каталоге, что и функция загрузки, но он не загружает данные.

Так что я придерживаюсь версии bulkDocs.

Вопросы

Прошу прощения за очень длинный пост, и после всей контекстуализации возникают вопросы:

  • Есть ли возможность настроить библиотеки sqlite в Реагировать на среду веб-приложений?
  • И без всякого бэкенда?
  • Каков рекомендуемый способ переключения между моими таблицами .json?
  • Должен ли я удалить предыдущий сохраненный и загрузить следующий?
  • Или загружать каждую таблицу вручную, а затем выгружать их с помощью сумка-свалка-кли?

Я надеюсь, что все хорошо объяснено, и я буду рад прояснить любые вопросы, которые могут у вас возникнуть.

Спасибо за уделенное время!

Возможный ответ


Итак, я смог решить свою проблему, создав такой код.

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 Bramwell 01.03.2019 17:29

Я отредактировал вопрос, Мартин, извините за неясные части.

Giovanni Klein Campigoto 01.03.2019 18:02

Хорошо, но тогда я не понимаю, почему вы создали код для импорта данных из файлов JSON. Как я упоминал в другом вопросе, во второй части сообщения блога Готовые базы данных с PouchDB есть пример того, как быстро инициализировать PouchDB из файлов JSON. До вашего недавнего обновления вы, кажется, говорили, что успешно использовали это. Вы?

Martin Bramwell 01.03.2019 18:08

Ах да, я забыл упомянуть, что когда вы пытаетесь загрузить файлы с помощью pouchdb-load, он запускает команду JSON.parse, которая ожидает, что ваш JSON является строкой, иначе она терпит неудачу, несмотря на то, что она является допустимой. JSON так нежизнеспособен?

Giovanni Klein Campigoto 01.03.2019 18:19

Это ошибка, которую выдает JSON.parse: SyntaxError: «JSON.parse: неожиданный символ в строке 1, столбце 2 данных JSON», мне потребовалось некоторое время, чтобы понять, что это ошибка для типа JSON. Вы можете проверить это здесь: developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…

Giovanni Klein Campigoto 01.03.2019 18:28

извините, теперь неясно, решили ли вы свою предыдущую проблему с pouchdb-load, или вы знаете, что это такое, но не можете ее решить. Кроме того, решение проблемы pouchdb-load решит весь вопрос, или вы все еще хотите создавать свои собственные объемные документы?

Martin Bramwell 01.03.2019 18:33

Мне пришлось создать класс DbService, потому что pouchdb-load не может анализировать простой файл .json, он должен быть НИТЬ, иначе он не будет работать. Вот почему я использую bulkDocs, это единственный способ импортировать файлы в хранилище IndexedDB. Проблема в том, что если я выдаю команду для импорта другого файла, они конфликтуют, и мне нужно переключаться между файлами, чтобы пользователь мог запрашивать другие таблицы, которые хранятся в этих файлах.

Giovanni Klein Campigoto 01.03.2019 18:40

Но в этом примере ожидается, что db.load('turtles.txt') извлечет файл с исходного сервера. Конечно, «SyntaxError: «JSON.parse: неожиданный символ в строке 1, столбце 2 данных JSON»» означает, что «turtles.txt» не найден.

Martin Bramwell 01.03.2019 18:48

Да, поэтому я изменил свой код, чтобы он выполнял _db.load('table_name.json'), и он находится в той же папке, но вызывает ошибку JSON.parse, поэтому я не знаю, что делать.

Giovanni Klein Campigoto 01.03.2019 19:14

Не могли бы вы посмотреть, что произойдет, если вы измените имя на что-то вроде _db.load('causeError.json', просто чтобы проверить, действительно ли он загружает файл. Кроме того, что произойдет, если вы проверите файл в JSON красивая печать?

Martin Bramwell 01.03.2019 20:07

JSON действителен, но, похоже, нет возможности загрузить файлы, так как для загрузки используется JSON.parse, а его содержимое должно быть строкой.

Giovanni Klein Campigoto 03.03.2019 13:50

Итак, по сути db.load() как описано в части 2 "Загрузка из файла дампа" статьи Готовые базы данных с PouchDB в корне сломан и работать больше не будет?

Martin Bramwell 03.03.2019 20:30

Я не уверен в этом, на самом деле это не работает для моей проблемы, потому что он не может загрузить простой файл .json, а только его строковое представление.

Giovanni Klein Campigoto 04.03.2019 16:08

У меня есть подозрение, что основной причиной ваших трудностей все время были двойные кавычки в столбцах varchar. Стоит проверить это, а не предполагать, что pouchdb-load «... не удается загрузить простой файл .json ...»

Martin Bramwell 04.03.2019 18:59
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
14
3 269
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Для будущих читателей, вот как вы можете решить проблему.

  1. Если у вас есть файл SQLite, перейдите к моему предыдущему заданному вопросу: Как правильно загружать готовые базы данных SQlite с PouchDB или без него в приложении React
  2. Найдите ответ на вопрос и выполните команды sqlite3 соответственно, выводя файлы .json.

  3. При вводе команды SELECT, если у вас есть какие-либо столбцы со специальными символами, такими как пробел или точки в имени, используйте оператор квадратных ракеток в имени столбца [ ]:

    пример sqlite3 ".output rslt.json" "SELECT '{ \"идентификатор \": \"некотораяТаблица' || SUBSTR(\"000000000\" || id, LENGTH(\"000000000\" || id) - 8, 9) || '\", \"анаттр\": \"' || анаттр || '\", \"anothe.rattr\": \"' || [anoth.erattr] || '\" },' FROM some_table;";

  4. У меня возникла проблема, в некоторых строках таблицы были такие двойные кавычки: "Attr": "Lorem ipsum "долор"". Это вызывает ошибку синтаксического анализа. Для исправления используйте оператор управляющего символа \ перед кавычками: "Lorem ipsum \"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!!! Помните, это не оптимально! Я буду работать над оптимизированным подходом для этого.

Спасибо и спасибо Мартин за вашу помощь!

Вы можете убедиться, что ваш запрос на миграцию данных Sqlite последовательно экспортирует чистый чистый JSON с помощью строковой функции Sqlite REPLACE() Таким образом, вместо '\", \"anothe.rattr\": \"' || [anoth.erattr] || '\" у вас будет '\", \"anothe.rattr\": \"' || REPLACE([anoth.erattr], '"', '\"' || '\". (Отказ от ответственности: не проверено! Возможно, вам удалось избежать некоторых кавычек и, возможно, даже избежать экранирования.)

Martin Bramwell 04.03.2019 19:07

Другие вопросы по теме