How do I check if an IndexedDB database already exists? - javascript

I'm working on restaurant website (client-side project) and facing this problem, I want to make an admin page will show me all the orders placed by the customers and the way I choose that to save the order details in local storage then save it in this indexedDB then display the (the orders) at the admin page so I made this code and it work all good I guess to save the order and all customer details
document.getElementById('submittheorder').onclick = function() {
let i = 0;
const versionDB = 1;
let indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB || window.shimIndexedDB;
var open = indexedDB.open("CustomersOrders", versionDB);
open.onupgradeneeded = function() {
let db = open.result;
let store = db.createObjectStore("OrdersTable", {
keyPath: "id"
});
let index = store.createIndex("CIndex", ["FullName", "Order", "House", "Road", "Block"]);
};
open.onsuccess = function() {
let db = open.result;
let tx = db.transaction("OrdersTable", "readwrite");
let store = tx.objectStore("OrdersTable");
let index = store.index("CIndex");
store.put({
FullName: (sessionStorage.getItem("Cfullname")),
Order: (sessionStorage.getItem("order")),
House: (sessionStorage.getItem("CHouse")),
Road: (sessionStorage.getItem("CRoad")),
Block: (sessionStorage.getItem("CBlock"))
});
tx.oncomplete = function() {
db.close();
location.href = "Thanks.html";
};
}
}
Now the problem is I want to retrieve all the orders and the details for each object to the admin page
the second problem is that i want to check if the database already exist then insert new object not make a new database and save only one object, in a nutshell i want only one database to make and next times save the orders at that database.
Thank you :)

You can place this logic in the function that handles an upgrade event. There are essentially two ways. You can check if object stores and indices exist, using for example db.objectStoreNames.contains(), or you can compare versions by accessing the version properties from the database object or the event object.
For example, you would want to only create an object store if it did not already exist. If it does not already exists, then you know this is when your database is created.

Related

How to create a module using mongoose for sharing a changing DB connection

i've been working on an app(Node.js with MongoDB using mongoose), and the server connects to 2 different databases, 1 generic containing username and password pairs for user authentication. Then, when the user signs in, I want to connect to a different database, named after the user's userId. I managed to create a module for sharing the generic UA database, but it's more difficult with the second one, since it doesn't open with the connection, but later on, when the user signs in. I guess i got inspired by the idea of react context kind of sharing.
So far i've got something like this
const mongoose = require("mongoose");
/*
UA = User Authentication
US = User Specific
DB = DataBase
*/
const UA_DB = mongoose.createConnection(/*...*/);
);
const User = UA_DB.model("User", require("../../data-schemas/user"));
let US_DB, Order, Item, Ingredient, Place;
console.log("opened UA database");
function sendUserId(newUserId) {
userId = newUserId;
US_DB = mongoose.createConnection(/*... ${newUserId} ...*/ );
Order = US_DB.model("Order", require("../../data-schemas/order"));
Item = US_DB.model("Item", require("../../data-schemas/item"));
Ingredient = US_DB.model(
"Ingredient",
require("../../data-schemas/ingredient")
);
Place = US_DB.model("Place", require("../../data-schemas/place"));
console.log("opened US database");
}
module.exports = {
UA_DB: {
User,
},
US_DB: {
Order,
Item,
Ingredient,
Place,
},
sendUserId,
};
Now, if I hadn't made it clear, the first, UA_DB works just fine, the user signs in just fine... When it comes to the US_DB i always get undefined as values(Cannot read property 'find' of undefined). I suspect the problem could be, that the exported value doesn't update with the value of the variables. Any ideas, how this could be solved?
Well, i figured it out. Instead of using precise values I use a function to return them, and to connect to the database.UserId is stored in a token, so after verification i check whether i am already connected to the right database (with the userId variable, which stores previous values) and then return curretn values of the models now my code looks something like this
const mongoose = require("mongoose");
/*
UA = User Authentication
US = User Specific
DB = DataBase
*/
const UA_DB = mongoose.createConnection(/* ... */
);
const User = UA_DB.model("User", require("../../data-schemas/user"));
let US_DB,
Order,
Item,
Ingredient,
Place = "some default value";
console.log("opened UA database");
let userId = "";
function getUS_DBModels(newUserId) {
if (newUserId !== userId) {
userId = newUserId;
US_DB = mongoose.createConnection(`...${userId}...`
);
Order = US_DB.model("Order", require("../../data-schemas/order"));
Item = US_DB.model("Item", require("../../data-schemas/item"));
console.log("opened a US_DB connection");
Ingredient = US_DB.model(
"Ingredient",
require("../../data-schemas/ingredient")
);
Place = US_DB.model("Place", require("../../data-schemas/place"));
}
return {
Order, Item, Ingredient, Place
}
}
module.exports = {
UA_DB: {
User,
},
getUS_DBModels,
};
For anyone wondering, in different modules you can access the values like this
const dbHandler = require("./path/to/the/module");
const { Item } = dbHandler.getUS_DBModels("UserId");

How can I `put` new values in an already existing objectStore in an already existing indexedDB?

I am tying myself up in knots trying to update a series of four entries in an objectStore in an indexedDB.
This is what I want to achieve (in pseudo-code):
let myDatabase = indexedDB('myDatabase', 1);
let myObjectStore = myDatabase.myObjectStore;
myObjectStore.entry1 = 'newValue1';
myObjectStore.entry2 = 'newValue2';
myObjectStore.entry3 = 'newValue3';
myObjectStore.entry4 = 'newValue4';
But of course, it isn't anything like that straightforward.
I understand I need to use put. But, despite numerous attempted approaches, I can't get further than that.
I have got as far as successfully setting up and populating the objectStore in the first place when the indexedDB is first created:
// SET UP VALUES OBJECT
let valuesObject = {
entry1 : 'a',
entry2 : 'b',
entry3 : 'c',
entry4 : 'd'
};
// SET UP INDEXED DATABASE
const setUpIndexedDatabase = (valuesObject) => {
let database
const databaseVersion = 1;
const databaseName = \'myDatabase\';
const databaseOpenRequest = indexedDB.open(databaseName, databaseVersion);
databaseOpenRequest.onupgradeneeded = () => {
database = databaseOpenRequest.result;
let myObjectStore = database.createObjectStore('myObjectStore');
myObjectStore.transaction.oncomplete = () => {
let objectStoreValues = database.transaction('Values', 'readwrite').objectStore('Values');
const valuesEntries = Object.entries(valuesObject);
for (let i = 0; i < valuesEntries.length; i++) {
objectStoreValues.add(valuesEntries[i][1], valuesEntries[i][0]);
}
}
}
databaseOpenRequest.onsuccess = () => {
database = databaseOpenRequest.result;
// >>> THIS IS THE BIT THAT I NEED TO WRITE <<<
database.close();
}
}
setUpIndexedDatabase(valuesObject);
So far, so good. The code above fires the onupgradeneeded event if no database exists yet, which creates myObjectStore and populates it with four key-value pairs.
But if the database does exist and already contains myObjectStore, then every variation of code I have written using put fails to update the values for the keys and returns various errors - and quite often no errors at all.
All I want to do is update values in the database.
I think the problem is that I don't know how to use put properly when the Database Version remains unchanged and onupgradeneeded doesn't fire.
If you want to update an already existing value in the database, you can do so with the following code (as example, I am updating the entry1 entry):
databaseOpenRequest.onsuccess = function(event) {
db = event.target.result;
const objectStore = db.transaction('myObjectStore', 'readwrite').objectStore('myObjectStore');
const request = objectStore.put('e', 'entry1');
request.onerror = function(event) {
// There was an error while updating.
};
request.onsuccess = function(event) {
// The update was successful.
};
}

Create index on already existing objectStore

As an example on basic setup one index is created.
db.onupgradeneeded = function(event) {
var db = event.target.result;
var store = db.createObjectStore('name', { keyPath: 'id' });
store.createIndex('by name', 'name', { unique: false });
};
Question:
Is it possible to create/append more indexes to the same objectStore on the future versionupdate? Since if I try:
db.onupgradeneeded = function(event) {
var db = event.target.result;
var store = db.createObjectStore('name', { keyPath: 'id' });
store.createIndex('by newName', 'newName', { unique: false });
};
It throws an error that current objectStore does already exist. An if I try to create store reference using transaction:
db.onupgradeneeded = function(event) {
var db = event.target.result;
var store = db.transaction('name', 'readwrite').objectStore('name');
store.createIndex('by newName', 'newName', { unique: false });
};
It throws that version change transaction is currently running
Yes it is possible. It can be a bit confusing at first. You want to get the existing object store via the implicit transaction created for you within onupgradeneeded. This is a transaction of type versionchange which is basically like a readwrite transaction but specific to the onupgradeneeded handler function.
Something like this:
var request = indexedDB.open(name, oldVersionPlusOne);
request.onupgradeneeded = myOnUpgradeNeeded;
function myOnUpgradeNeeded(event) {
// Get a reference to the request related to this event
// #type IDBOpenRequest (a specialized type of IDBRequest)
var request = event.target;
// Get a reference to the IDBDatabase object for this request
// #type IDBDatabase
var db = request.result;
// Get a reference to the implicit transaction for this request
// #type IDBTransaction
var txn = request.transaction;
// Now, get a reference to the existing object store
// #type IDBObjectStore
var store = txn.objectStore('myStore');
// Now, optionally inspect index names, or create a new index
console.log('existing index names in store', store.indexNames);
// Add a new index to the existing object store
store.createIndex(...);
}
You also will want to take care to increment the version so as to guarantee the onupgradeneeded handler function is called, and to represent that your schema (basically the set of tables and indices and properties of things) has changed in the new version.
You will also need to rewrite the function so that you only create or make changes based on the version. You can use event.oldVersion to help with this, or things like db.objectStoreNames.contains.
Something like this:
function myOnUpgradeNeeded(event) {
var is_new_db = isNaN(event.oldVersion) || event.oldVersion === 0;
if(is_new_db) {
var db = event.target.result;
var store = db.createObjectStore(...);
store.createIndex('my-initial-index');
// Now that you decided you want a second index, you also need
// to do this for brand new databases
store.createIndex('my-second-new-index');
}
// But if the database already exists, we are not creating things,
// instead we are modifying the existing things to get into the
// new state of things we want
var is_old_db_not_yet_current_version = !isNaN(event.oldVersion) && event.oldVersion < 2;
if(is_old_db_not_yet_current_version) {
var txn = event.target.transaction;
var store = txn.objectStore('store');
store.createIndex('my-second-new-index');
}
}
Pay close attention to the fact that I used event.target.transaction instead of db.transaction(...). These are not at all the same thing. One references an existing transaction, and one creates a new one.
Finally, and in addition, a personal rule of mine and not a formal coding requirement, you should never be using db.transaction() from within onupgradeneeded. Stick to modifying the schema when doing upgrades, and do all data changes outside of it.

parse server: include pointer in live query in javascript sdk

I am using parse server to live query a class containing rows with pointers.
When I use include() in the normal query it get all the data of the pointer but in the live query I only get the objectId
Code:
var currentUser = Parse.User.current();
const Conversation = Parse.Object.extend("conversations");
var fromQuery = new Parse.Query(Conversation);
fromQuery.equalTo("from", currentUser );
var toQuery = new Parse.Query(Conversation);
toQuery.equalTo("to", currentUser);
var mainQuery = Parse.Query.or(fromQuery, toQuery);
mainQuery.include("to")
mainQuery.include("from")
mainQuery.include("lastMessage")
// FIXME: DEBUG:
this.convsubscription = mainQuery.subscribe();
mainQuery.find().then((conversations) => {
for (var i = 0; i < conversations.length; i++){
var object = conversations[i]
this.conversations.unshift(object);
}
})
this.convsubscription.on('update', (object) => {
// we will get the index of updated object
var index = this.conversations.findIndex(x => x.id == object.id);
console.log(index);
// then we will remove the old object and insert the updated one
this.conversations.splice(index, 1 ,object)
console.log(JSON.stringify(this.conversations[index].get('lastMessage')))
})
When I do JSON.stringify(this.conversations[index].get('lastMessage')) it only gives the objectId. I need a way to access the content of the pointer lastMessage
Regards
includeKey()/include() isn't supported in Live Queries:
this is a server side issue, the includeKey is ignored when subscribing to the query. The decision tree is processed synchronously after an object is saved on parse-server, therefore we don't have the opportunity to inject inclusions. We'd need to refactor the whole serverside logic in order to support those.
See related issues to keep track:
https://github.com/parse-community/ParseLiveQuery-iOS-OSX/issues/30
https://github.com/parse-community/parse-server/issues/1686

Resuing IDBTransaction in callbacks throws TransactionInactiveError

I'm developing a app which uses IndexedDB extensively. What I'm trying to do is save data of employees table and company table. Each employee belongs to a company and in employee object I've Company's ID and the objects of both of the entity will look like this.
Company's object:
{"id":1,"name":"ABC"}
Employee's object:
{"id":100,"name":"E1","company_id":1}
I'm saving company's details using auto-incremented key (called it appid), so my final object of company's look like this:
{"id":1,"name":"ABC","appid":1}
Where the appid will get auto-incremented as I insert records of company one by one. Now while inserting employee's object I want to find the localid(appid) of the company and save it in employee's object to make employee's object look like:
{"id":100,"name":"E1","company_id":1,"company_app_id":1}
I'm able to get the localid of the company by calling a method while saving employee's details, like:
var transaction = db.transaction(['employees'], 'readwrite');
var objStore = transaction.objectStore('employees');
var company_id=employeeobject.company_id;
companyDB.getCompanyById(company_id,function(companyObject){
transaction = db.transaction(['employees'], 'readwrite');
objStore = transaction.objectStore('employees');
// If I comment above two lines it throws me exception.
var request=objStore.put(employeeobject);
request.onsuccess = function (e) {
// using it for next insertion.
};
});
Problem with the above code is every time when I want to insert employee's data in table I need to reopen the trascation in callback function because if I don't open the transaction again it throws TransactionInactiveError.
I've searched for specific error on SO and found that Transaction get inactive as soon as it's no more used in current scope.
Above code work perfectly fine when I've couple of employee's objects.
But When I'm trying to execute the same code with ~1K of data it takes
(normal execution time x ~10).
By normal execution time I mean without fetching company's localid and saving employee's details directly.
So my question is, what is the best way I can insert the employee's data including company's localid with least execution time? Or Am I doing something wrong ?
It depends on how you're implementing companyDB.getCompanyById().
As presented, it's an asynchronous black box (maybe it's doing a network request?) And as you've discovered, Indexed DB transactions are only active (1) directly after creation and (2) in callbacks from requests made in that transaction, until "control returns to the event loop". Without further details, your best bet would be to batch the work - do the getCompanyById() lookups for N employees, then write those N records.
But from the description at the top "...data of employees table and company table..." maybe this is all within a single Indexed DB database, in which case just use a single transaction for everything:
var tx = db.transaction(['companies', 'employees'], 'readwrite');
employee_records.forEach(function(record) {
var company_id = record.company_id;
var req = tx.objectStore('companies').get(company_id);
req.onsuccess = function() {
var company = req.result;
record.company_app_id = company.app_id;
tx.objectStore('employees').put(record);
};
});
(I'm mangling your actual data/logic here, this is just to illustrate)
Hmm, maybe something like this helps?
function addCompany(db, company, callback) {
var tx = db.transaction('companies', 'readwrite');
var store = tx.objectStore('companies');
var request = store.add(company);
request.onsuccess = callback;
}
function addEmployee(db, employee, callback) {
var tx = db.transaction('employees', 'readwrite');
var store = tx.objectStore('employees');
var request = store.add(employee);
request.onsuccess = callback;
}
function addCompanyThenEmployee(db, company, employee, callback) {
addCompany(db, company, onAddCompany);
function onAddCompany(event) {
var newAppId = event.target.result;
employee.company_app_id = newAppId;
addEmployee(db, employee, callback);
}
}
var company = {'id': 1, 'name': 'xyz'};
var employee = {'id': 1, 'name': 'xyz'};
var request = indexedDB.open(...);
request.onsuccess = function(event) {
var db = event.target.result;
addCompanyThenEmployee(db, company, employee, onAddCompanyThenEmployee.bind(null, company, employee));
};
function onAddCompanyThenEmployee(company, employee, event) {
console.log('Added company', company, 'and employee', employee);
};

Categories

Resources