Create a database with IndexedBD
Tags: javascript, webdev, programming, 100daysofcode
Published: 2022-01-04 17:11:11

Before opening (creating) a database using IndexedDB we must verify that the browser has the necessary support, for this we create a function that we will use later when creating the database:

```jsx
function indexedDBSupport(){
    return 'indexedDB' in window;
}
```

Then we have to create a _request_ to open the database that returns an event (`success` or `error`) through the **IDBOpenDBRequest** object, which will allow us to access the event.

The `open(name, version)` function has two parameters, the first is the name of the database that identifies it within the client's browser, the second parameter is the version of our database, this is important since it will be defined a _Database Schema_ that will determine the structure of the objects to be stored, so if you want to change it, you just have to change the version of our database.

```jsx
// The version value is 1 by default
const request = window.indexedDB.open("MyDatabase", 1);
```

## Event handling
As mentioned above, once the request to open the database has been made, 3 events can be handled with their respective functions:

- `onerror`: If the creation or connection to the database fails.
- `onsuccess`: This is executed every time the database is connected or created.

- `onupgradeneeded`: This is executed only once, when the database is created or updated, so the structure of it (_Database Schema_) will be defined here.

> 💡 Once the request is made, we obtain the **IDBOpenDBRequest** object, in which the result of said request is stored.

```jsx
// Save the connection to the database in a global variable
// since it will later be used to carry out transactions
let db;

function createDatabase() {

    if (!indexedDBSupport()) throw new Error("Your browser doesn't support IndexedBD");

    const request = window.indexedDB.open('MyDatabase', 1);

// Event handling
    request.onerror = (e) => {
        console.error(`IndexedDB error: ${request.errorCode}`);
    };

    request.onsuccess = (e) => {
        console.info('Successful database connection');
        db = request.result;
    };

    request.onupgradeneeded = (e) => {
        console.info('Database created');
        const db = request.result;
        //...
    };

}
```

## Using `onupgradeneeded`
As mentioned above, this event is fired when the database is created for the first time or when its version is updated, so it is the ideal place to specify the _Database Schema_.

### Creating an Object Store (table)
We must define where the objects will be stored for the current version of our database. For this we create an instance of **IDBObjectStore** (represents an object store) using the `createObjectStore(name, options)` method, which has the following parameters:

- `name`: Name of the Object Store

- `options`: Optional parameter that contains the following attributes:

    - keypath: Specifies the name of the attribute that will contain the index with which it will identify each object.

    - autoIncrement: If the value is true, an incremental value will be given to the keyPath.

```jsx
//...

request.onupgradeneeded = (e) => {

    console.info('Database created');

    const db = request.result;

    const objectStore = db.createObjectStore('student', {keyPath: 'email'})
};

//...
```

> 💡 If you want to update the Object Store, bear in mind that it will have the new structure, but it will be empty, so is a good idea that, before creating the new Object Store, save the objects in another place and then delete the old Object Store and reinsert them into the new one.

### Creating Indexes (fields or attributes)
To create “fields” (_index_) in a "table" (_Object Store_), use the `createIndex(indexName, keyPath, options)` method of the **IDBObjectStore** object, which has the following parameters:

- `indexName`: It is the name by which the "field" is identified within the table.

- `keyPath`: It is the property of the object that will contain the value of the field. Most of the time the indexName and the keyPath have the same value, since it makes sense that the field is called the same as the property that will contain its value.

- `options`: The most useful property is `unique` which does not allow duplicate values ​​within the same index.

```jsx
//...

request.onupgradeneeded = (e) => {

    console.info('Database created');

    const db = request.result;

    const objectStore = db.createObjectStore('student', {keyPath: 'email'});

    // Indexes
    objectStore.createIndex("email", "email", { unique: true });
    objectStore.createIndex("name", "name", { unique: false });
    objectStore.createIndex("lastname", "lastname", { unique: false });
    objectStore.createIndex("age", "age", { unique: false });

};

//...
```

As it works based on requests, we can use the `complete` event to verify that the transaction was completed and the _Object Store_ was created successfully to perform some action later, if necessary.

```jsx
//...

request.onupgradeneeded = (e) => {

    console.info('Database created');

    const db = request.result;

    const objectStore = db.createObjectStore('student', {keyPath: 'email'});

    // Indexes
    objectStore.createIndex('email', 'email', { unique: true });
    objectStore.createIndex('name', 'name', { unique: false });
    objectStore.createIndex('lastname', 'lastname', { unique: false });
    objectStore.createIndex('age', 'age', { unique: false });

    // Transaction completed
    objectStore.transaction.oncompleted = (e)=> {
        console.log('Object store "student" created');
    }

};

//...
```