This guide will get you familiar with using OrbitDB in your JavaScript application. OrbitDB and IPFS both work in Node.js applications as well as in browser applications. (Windows is not supported yet though).
This guide is still being worked on and we would love to get [feedback and suggestions](https://github.com/orbitdb/orbit-db/issues) on how to improve it!
## Table of Contents
- [Background](#background)
- [Install](#install)
- [Setup](#setup)
- [Create a database](#create-a-database)
- [Address](#address)
- [Manifest](#manifest)
- [Keys](#keys)
- [Access Control](#access-control)
- [Public databases](#public-databases)
- [Add an entry](#add-an-entry)
- [Get an entry](#get-an-entry)
- [Persistency](#persistency)
- [Replicating a database](#replicating-a-database)
## Background
OrbitDB is a peer-to-peer database meaning that each peer has its own instance of a specific database. A database is replicated between the peers automatically resulting in an up-to-date view of the database upon updates from any peer. That is to say, the database gets pulled to the clients.
This means that each application contains the full database that they're using. This in turn changes the data modeling as compared to client-server model where there's usually one big database for all entries: in OrbitDB, the data should be stored, "partitioned" or "sharded" based on the access rights for that data. For example, in a twitter-like application, tweets would not be saved in a global "tweets" database to which millions of users write concurrently, but rather, ***each user would have their own database*** for their tweets. To follow a user, a peer would subscribe to a user's feed, ie. replicate their feed database.
OrbitDB supports multiple data models (see more details below) and as such the developer has a variety of ways to structure data. Combined with the peer-to-peer paradigm, the data modeling is important factor to build scalable decentralized applications.
This may not be intuitive or you might not be sure what the best approach would be and we'd be happy to help you decide on your data modeling and application needs, [feel free to reach out](https://github.com/orbitdb/orbit-db/issues)!
## Install
Install [orbit-db](https://github.com/orbitdb/orbit-db) and [ipfs](https://www.npmjs.com/package/ipfs) from npm:
```
npm install orbit-db ipfs
```
## Setup
Require OrbitDB and IPFS in your program and create the instances:
The first part, `/orbitdb`, specifies the protocol in use. The second part, an IPFS multihash `Qmd8TmZrWASypEp4Er9tgWP4kCNQnW4ncSnvjvyHQ3EVSU`, is the database manifest which contains the database info such as the name and type, and a pointer to the access controller. The last part, `first-database`, is the name of the database.
In order to replicate the database with peers, the address is what you need to give to other peers in order for them to start replicating the database.
The database address can be accessed as `db.address` from the database instance:
The second part of the address, the IPFS multihash `Qmdgwt7w4uBsw8LXduzCd18zfGXeTmBsiR8edQ1hSfzcJC`, is the manifest of a database. It's an IPFS object that contains information about the database.
Each entry in a database is signed by who created that entry. The signing key, the key that a peer uses to sign entries, can be accessed as a member variable of the database instance:
If you want to give access to other peers to write to a database, you need to get their public key in hex and add it to the access controller upon creating the database. If you want others to give you the access to write, you'll need to give them your public key (output of `orbitdb.key.getPublic('hex')`). For more information, see: [Access Control](https://github.com/orbitdb/orbit-db/blob/master/GUIDE.md#access-control).
You can specify the peers that have write-access to a database. You can define a set of peers that can write to a database or allow anyone write to a database. **By default and if not specified otherwise, only the creator of the database will be given write-access**.
***Note!*** *OrbitDB currently supports only write-access and the keys of the writers need to be known when creating a database. That is, the access rights can't be changed after a database has been created. In the future we'll support read access control and dynamic access control in a way that access rights can be added and removed to a database at any point in time without changing the database address. At the moment, if access rights need to be changed, the address of the database will change.*
Access rights are setup by passing an `access` object that defines the access rights of the database when created. OrbitDB currently supports write-access. The access rights are specified as an array of public keys of the peers who can write to the database.
```javascript
const ipfs = new IPFS()
ipfs.on('ready', async () => {
const orbitdb = new OrbitDB(ipfs)
const access = {
// Give write access to ourselves
write: [orbitdb.key.getPublic('hex')],
}
const db = await orbitdb.keyvalue('first-database', access)
To give write access to another peer, you'll need to get their public key with some means. They'll need to give you the output of their OrbitDB instance's key: `orbitdb.key.getPublic('hex')`.
We currently don't support parallel updates. Updates to a database need to be executed in a sequential manner. The write throughput is several hundreds or thousands of writes per second (depending on your platform and hardware, YMMV), so this shouldn't slow down your app too much. If it does, [lets us know](https://github.com/orbitdb/orbit-db/issues)!
Update the database one after another:
```javascript
await db.put('key1', 'hello1')
await db.put('key2', 'hello2')
await db.put('key3', 'hello3')
```
Not:
```javascript
// This is not supported atm!
Promise.all([
db.put('key1', 'hello1'),
db.put('key2', 'hello2'),
db.put('key3', 'hello3')
])
```
## Get an entry
To get a value or entry from the database, we call the appropriate query function which is different per database type.
Key-Value:
```javascript
const ipfs = new IPFS()
ipfs.on('ready', async () => {
const orbitdb = new OrbitDB(ipfs)
const db = await orbitdb.keyvalue('first-database')
OrbitDB saves the state of the database automatically on disk. This means that upon opening a database, the developer can choose to load locally the persisted before using the database. **Loading the database locally before using it is highly recommended!**
If the developer doesn't call `load()`, the database will be operational but will not have the persisted data available immediately. Instead, OrbitDB will load the data on the background as new updates come in from peers.
## Replicating a database
In order to have the same data, ie. a query returns the same result for all peers, an OrbitDB database must be replicated between the peers. This happens automatically in OrbitDB in a way that a peer only needs to open an OrbitDB from an address and it'll start replicating the database.
To know when database was updated, we can listen for the `replicated` event of a database: `db2.events.on('replicated', () => ...)`. When the `replicated` event is fired, it means we received updates for the database from a peer. This is a good time to query the database for new results.
Is this guide missing something you'd like to understand or found an error? Please [open an issue](https://github.com/orbitdb/orbit-db/issues) and let us know what's missing!