mirror of
https://github.com/orbitdb/orbitdb.git
synced 2025-06-03 20:56:37 +00:00
commit
008c97244b
@ -1,10 +1,10 @@
|
||||
# Databases
|
||||
|
||||
DB provides a variety of different data stores with a common interface.
|
||||
OrbitDB is a multi-model database which means various different types of data models can be used and custom data models can be created.
|
||||
|
||||
## Types
|
||||
|
||||
OrbitDB provides four types of data stores:
|
||||
By default OrbitDB provides four types of databases:
|
||||
|
||||
- Events
|
||||
- Documents
|
||||
@ -18,7 +18,7 @@ const type = 'documents'
|
||||
orbitdb.open('my-db', { type })
|
||||
```
|
||||
|
||||
If no type is specified, Events will the default database type.
|
||||
If no type is specified, Events will the default database type. The type of a database, when created, is stored in the database's manifest. When opening a database, OrbitDB will read the type from the manifest and return the correct database type automatically.
|
||||
|
||||
## Address
|
||||
|
||||
@ -28,7 +28,9 @@ When a database is created, it is assigned an address by OrbitDB. The address co
|
||||
/orbitdb/zdpuAmrcSRUhkQcnRQ6p4bphs7DJWGBkqczSGFYynX6moTcDL
|
||||
```
|
||||
|
||||
The first part, `/orbitdb`, specifies the protocol in use. The second part, an IPFS multihash `zdpuAmrcSRUhkQcnRQ6p4bphs7DJWGBkqczSGFYynX6moTcDL`, is the database manifest which contains the database info such as the name and type, and a pointer to the access controller.
|
||||
The first part, `/orbitdb`, specifies the protocol in use.
|
||||
|
||||
The second part, an IPFS multihash `zdpuAmrcSRUhkQcnRQ6p4bphs7DJWGBkqczSGFYynX6moTcDL`, is the database manifest which contains the database info such as the name and type, and a pointer to the access controller.
|
||||
|
||||
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.
|
||||
|
||||
@ -49,7 +51,7 @@ The second part of the address, the IPFS multihash `zdpuAmrcSRUhkQcnRQ6p4bphs7DJ
|
||||
|
||||
An example of a manifest is given below:
|
||||
|
||||
```json
|
||||
```js
|
||||
{
|
||||
name: 'my-db',
|
||||
type: 'events',
|
||||
@ -57,7 +59,7 @@ An example of a manifest is given below:
|
||||
}
|
||||
```
|
||||
|
||||
The manifest is simply an [IPLD data structure](https://ipld.io/docs/) which can be retrived from IPFS using the manifest's hash:
|
||||
The manifest is an [IPLD data structure](https://ipld.io/docs/) which can be retrived from IPFS using the manifest's hash:
|
||||
|
||||
```js
|
||||
import { create } from 'ipfs-core'
|
||||
@ -92,30 +94,30 @@ const { value } = await Block.decode({ bytes, codec, hasher })
|
||||
console.log('manifest', value)
|
||||
```
|
||||
|
||||
## Opening a new database
|
||||
## Creating a new database
|
||||
|
||||
Opening a default event store:
|
||||
Creating a default event store:
|
||||
|
||||
```js
|
||||
const orbitdb = await OrbitDB()
|
||||
await orbitdb.open('my-db')
|
||||
```
|
||||
|
||||
Opening a documents database:
|
||||
Creating a documents database:
|
||||
|
||||
```js
|
||||
const orbitdb = await OrbitDB()
|
||||
await orbitdb.open('my-db', { type: 'documents' })
|
||||
```
|
||||
|
||||
Opening a keyvalue database:
|
||||
Creating a keyvalue database:
|
||||
|
||||
```js
|
||||
const orbitdb = await OrbitDB()
|
||||
await orbitdb.open('my-db', { type: 'keyvalue' })
|
||||
```
|
||||
|
||||
Opening a database and adding meta
|
||||
Creating a database and adding meta
|
||||
|
||||
```js
|
||||
const meta = { description: 'A database with metadata.' }
|
||||
@ -123,7 +125,7 @@ const orbitdb = await OrbitDB()
|
||||
await orbitdb.open('my-db', { meta })
|
||||
```
|
||||
|
||||
## Loading an existing database
|
||||
## Opening an existing database
|
||||
|
||||
```js
|
||||
const orbitdb = await OrbitDB()
|
||||
@ -140,7 +142,7 @@ Database types such as **documents** and **keyvalue** expose the `put` function
|
||||
|
||||
```js
|
||||
const orbitdb = await OrbitDB()
|
||||
const db = await orbitdb.open('my-db', { type: keyvalue })
|
||||
const db = await orbitdb.open('my-db', { type: 'keyvalue' })
|
||||
const hash = await db.put('key', 'value')
|
||||
```
|
||||
|
||||
@ -158,7 +160,7 @@ To delete an item from a database, use the `del` function:
|
||||
|
||||
```js
|
||||
const orbitdb = await OrbitDB()
|
||||
const db = await orbitdb.open('my-db', { type: keyvalue })
|
||||
const db = await orbitdb.open('my-db', { type: 'keyvalue' })
|
||||
const hash = await db.put('key', 'value')
|
||||
await db.del(hash)
|
||||
```
|
||||
@ -167,7 +169,7 @@ await db.del(hash)
|
||||
|
||||
The power of OrbitDB lies in its ability to replicate databases across distributed systems that may not always be connected.
|
||||
|
||||
A simple replication process between two databases can be accomplished by listening for updates and iterating over the record set as those updates occur.
|
||||
A simple way to replicate a database between peers can be accomplished by opening a database, listening for updates and iterating over the records as those updates occur.
|
||||
|
||||
```js
|
||||
import { create } from 'ipfs-core'
|
||||
@ -187,10 +189,10 @@ await db1.add('hello world')
|
||||
// database heads will be synchronized.
|
||||
const db2 = await orbitdb2.open(db1.address)
|
||||
|
||||
// We only have the heads of db1. To replicate all of db1's records, we will
|
||||
// We only have the latest record of db1. To replicate all of db1's records, we will
|
||||
// need to iterate over db1's entire record set.
|
||||
// We can determine when heads have been synchronized from db1 to db2 by
|
||||
// listening for the "update" event and iterating over the record set.
|
||||
// listening for the "update" event and iterating over the record set.
|
||||
db2.events.on('update', async (entry) => {
|
||||
for await (const record of db2.iterator()) {
|
||||
console.log(record)
|
||||
@ -205,10 +207,10 @@ To learn more, check out [OrbitDB's sychronization protocol](https://orbitdb.org
|
||||
|
||||
## Building a custom database
|
||||
|
||||
OrbitDB can be extended to use custom or third party data stores. To implement a custom database, ensure the Database object is extended and that the OrbitDB database interface is implement. The database will also require a unique type.
|
||||
OrbitDB can be extended to use custom data models and database types. To implement a custom database, ensure the Database object is extended and that the OrbitDB database interface is implement. The database will also require a unique type.
|
||||
|
||||
```js
|
||||
const CustomStore = async ({ OpLog, Database, ipfs, identity, address, name, access, directory, storage, meta, syncAutomatically, indexBy = '_id' }) => {
|
||||
const CustomDB = async ({ OpLog, Database, ipfs, identity, address, name, access, directory, storage, meta, syncAutomatically }) => {
|
||||
const database = await Database({ OpLog, ipfs, identity, address, name, access, directory, storage, meta, syncAutomatically })
|
||||
|
||||
const { addOperation, log } = database
|
||||
@ -242,7 +244,7 @@ const CustomStore = async ({ OpLog, Database, ipfs, identity, address, name, acc
|
||||
|
||||
return {
|
||||
...database,
|
||||
type: 'customstore',
|
||||
type: 'customdb',
|
||||
put,
|
||||
del,
|
||||
get,
|
||||
@ -251,4 +253,4 @@ const CustomStore = async ({ OpLog, Database, ipfs, identity, address, name, acc
|
||||
}
|
||||
```
|
||||
|
||||
[Documents](../src/db/documents.js), [Events](../src/db/events.js) and [KeyValue](../src/db/keyvalue.js) provide good examples of how a database is implemented in OrbitDB.
|
||||
[Documents](../src/db/documents.js), [Events](../src/db/events.js) and [KeyValue](../src/db/keyvalue.js) provide good examples of how a database is implemented in OrbitDB and how to add the logic for returning records from the database (the state of the database).
|
||||
|
@ -1,14 +1,14 @@
|
||||
# Identities
|
||||
|
||||
An identity is a cryptographically signed public key which can be used to sign and verify various data. Within OrbitDB, the main objective of an identity is verify write access to a database's log and, if allowed, to sign each entry as it is added to the log.
|
||||
In OrbitDB, an identity is a cryptographically signed public key which is used to verify write access to a database's operations log and, if allowed, to sign each database update as it is added to the operations log.
|
||||
|
||||
`Identities` provides methods to manage one or more identities and includes functionality for creating, retrieving, signing and verifying an identity as well as signing and verifying messages using an existing identity.
|
||||
`Identities` provides methods to manage one or more identities and includes functionality for creating, retrieving, signing and verifying an identity and, internally, it is used to sign and verify database updates.
|
||||
|
||||
## Creating an identity
|
||||
|
||||
An identity can be created by using the `createIdentity` function.
|
||||
|
||||
A root key is used to create a new key with the "id" of the root key's public key, Using the derived private key, the root public key is signed. This is known as the "signed message".
|
||||
A root key is used to create a new key with the "id" of the root key's public key. Using the derived private key, the root public key is signed.
|
||||
|
||||
A new identity is signed using the root key's private key. The identity is consists of the signed message and the derived public key concatenated together ("signed identity")
|
||||
|
||||
@ -60,16 +60,16 @@ const identity = identities.createIdentity({ id })
|
||||
There are different ways to customize the location of the key store.
|
||||
|
||||
To change the keystore using `OrbitDB`, pass a custom directory:
|
||||
```
|
||||
```js
|
||||
// This will create a key store under ./different-path/key-store
|
||||
const orbitdb = await OrbitDB({ directory: './different-path' })
|
||||
// Be aware that this will change the base path to the database as well.
|
||||
```
|
||||
|
||||
To change the keystore using the KeyStore function, pass a custom path to the `KeyStore` function:
|
||||
```
|
||||
```js
|
||||
// This will create a key store under ./different-key-store.
|
||||
const path = ./different-key-store
|
||||
const path = './different-key-store'
|
||||
const keystore = await KeyStore({ path })
|
||||
|
||||
// keystore can now be used with other functions, for example:
|
||||
@ -77,15 +77,15 @@ const identities = await Identities({ keystore })
|
||||
```
|
||||
|
||||
To specify a different keystore path using `Identities`, pass a custom path to the `Identities` function:
|
||||
```
|
||||
```js
|
||||
/// This will create a KeyStore under ./different-identities-path
|
||||
const path = ./different-identities-path
|
||||
const path = './different-identities-path'
|
||||
const identities = await Identities({ path })
|
||||
```
|
||||
|
||||
## Identity as a linked data object
|
||||
|
||||
The identity object is stored just like any other [IPLD data structure](https://ipld.io/docs/) and can therefore be retrieved from IPFS using the identity's hash:
|
||||
The identity object is stored like any other [IPLD data structure](https://ipld.io/docs/) and can therefore be retrieved from IPFS using the identity's hash:
|
||||
|
||||
```js
|
||||
import { create } from 'ipfs-core'
|
||||
@ -99,7 +99,7 @@ import { CID } from 'multiformats/cid'
|
||||
const ipfs = await create()
|
||||
|
||||
const identities = await Identities({ ipfs })
|
||||
const identity = await identities.createIdentity({ id: 'me'})
|
||||
const identity = await identities.createIdentity({ id: 'me' })
|
||||
|
||||
const cid = CID.parse(identity.hash, base58btc)
|
||||
|
||||
@ -116,9 +116,9 @@ const { value } = await Block.decode({ bytes, codec, hasher })
|
||||
console.log('identity', value)
|
||||
```
|
||||
|
||||
The resulting output is a JSON object containing the identity information:
|
||||
The resulting output is an object containing the identity information:
|
||||
|
||||
```json
|
||||
```js
|
||||
{
|
||||
id: '031a7bf5f233ad9dccb2a305edfd939f0c54f0ed2e270c4ac390d91ecd33d0c28f',
|
||||
type: 'publickey',
|
||||
@ -139,16 +139,18 @@ const type = 'custom'
|
||||
|
||||
// check whether the identity was signed by the identity's id.
|
||||
const verifyIdentity = identity => {
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
// The identity provider.
|
||||
const MyCustomIdentityProvider = ({ keystore }) => {
|
||||
const getId = async ({ id } = {}) => {
|
||||
|
||||
// return the "root" identity managed by the custom identity provider,
|
||||
// eg. a public key or a wallet address
|
||||
}
|
||||
|
||||
const signIdentity = async (data, { id } = {}) => {
|
||||
|
||||
const signIdentity = async (publicKeyAndIdSignature) => {
|
||||
// sign the publicKeyAndIdSignature using the custom identity provider system
|
||||
}
|
||||
|
||||
return {
|
||||
@ -162,9 +164,11 @@ export { MyCustomIdentityProvider as default, verifyIdentity, type }
|
||||
|
||||
To use it, add it to the list of known identity providers:
|
||||
|
||||
```javascript
|
||||
import as MyCustomIdentityProvider from 'my-custom-identity-provider'
|
||||
```js
|
||||
import { addIdentityProvider } from 'orbit-db'
|
||||
import MyCustomIdentityProvider from 'my-custom-identity-provider'
|
||||
addIdentityProvider(MyCustomIdentityProvider)
|
||||
const identity = await createIdentity({ id: 'some id', type: 'custom' })
|
||||
```
|
||||
|
||||
where my-custom-identity-provider is the custom module.
|
||||
where my-custom-identity-provider is the custom module.
|
||||
|
@ -1,8 +1,8 @@
|
||||
# Replication
|
||||
|
||||
Below is a simple replication example. Both peers run within the same Node daemon.
|
||||
Below is a simple replication example. Both peers run within the same Nodejs process.
|
||||
|
||||
```
|
||||
```js
|
||||
import { OrbitDB } from 'orbit-db'
|
||||
import { create } from 'ipfs-core'
|
||||
|
||||
@ -19,9 +19,6 @@ const config1 = {
|
||||
MDNS: {
|
||||
Enabled: true,
|
||||
Interval: 0
|
||||
},
|
||||
webRTCStar: {
|
||||
Enabled: false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -37,9 +34,6 @@ const config2 = {
|
||||
MDNS: {
|
||||
Enabled: true,
|
||||
Interval: 0
|
||||
},
|
||||
webRTCStar: {
|
||||
Enabled: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,27 +6,27 @@ Which storage strategy is chosen depends on the requirements of the application.
|
||||
|
||||
## Storage types
|
||||
|
||||
OrbitDB is bundled with the following storage:
|
||||
OrbitDB is bundled with the following storages:
|
||||
|
||||
- IPFSBlockStorage: IPFS block level storage,
|
||||
- LevelStorage: LevelDB-based storage,
|
||||
- LRUStorage: A Least Recently Used cache,
|
||||
- MemoryStorage: A memory only array,
|
||||
- MemoryStorage: In-memory storage,
|
||||
- ComposedStorage: Combines two storages, eg. LRUStorage and IPFSBlockStorage.
|
||||
|
||||
All storage objects expose two common functions, `put` for adding a record and `get` for retrieving a record. This allows for storage to be easily swapped in and out based on the needs of the database solution.
|
||||
|
||||
### Composed storage
|
||||
|
||||
ComposedStorage combines two of the above storage objects. This reduces the need for performance and capability trade-offs because a combination of storage mechanisms can be used for a balance of speed vs memory usage. For example, MemoryStorage plus LevelStorage can be used for fast retrieval plus semi-permanent data storage, or LRU for efficient caching of frequently accessed items plus IPFSBlockStorage for replication.
|
||||
ComposedStorage combines two of the above storage objects. This reduces the need for performance and capability trade-offs because a combination of storage mechanisms can be used for a balance of speed vs memory usage. For example, MemoryStorage plus LevelStorage can be used for fast retrieval plus semi-permanent (local) data storage, or LRU for efficient caching of frequently accessed items plus IPFSBlockStorage for distributed storage.
|
||||
|
||||
To use composed storage, create two storage objects and then pass them to an instance of `ComposedStorage`:
|
||||
|
||||
```js
|
||||
const memoryStorage = await MemoryStorage()
|
||||
const levelStorage = await LevelStorage()
|
||||
const ipfsStorage = await IPFSBlockStorage()
|
||||
|
||||
const composedStorage = await ComposedStorage(memoryStorage, levelStorage)
|
||||
const composedStorage = await ComposedStorage(memoryStorage, ipfsStorage)
|
||||
```
|
||||
|
||||
The order in which primary storage is passed to ComposedStorage is important. When accessed, ComposedStorage will attempt to retrieve the data from the first storage mechanism, so this should be the performance-based storage. If not found, ComposedStorage will attempt to retrieve the data from the second storage; this will likely be some kind of permanent storage mechanism.
|
||||
@ -41,7 +41,7 @@ const headsStorage = await MemoryStorage()
|
||||
const db = await orbitdb.open('my-db', { entryStorage, headsStorage })
|
||||
```
|
||||
|
||||
## Implementing a third party storage solution
|
||||
## Implementing a custom storage solution
|
||||
|
||||
Any storage mechanism can be used with OrbitDB provided it implements the OrbitDB storage interface. Once created, simply pass the storage instance to OrbitDB:
|
||||
|
||||
@ -112,4 +112,4 @@ It is recommended that all functions be defined for API consistency, but do not
|
||||
const close = async () => {}
|
||||
```
|
||||
|
||||
See the [various storage implementations](../src/storage) to see how custom storage should be structured for compatibility with OrbitDB.
|
||||
See the [various storage implementations](../src/storage) to see how custom storage should be structured for compatibility with OrbitDB.
|
||||
|
@ -13,46 +13,32 @@ IPFS is also required:
|
||||
npm install ipfs-core
|
||||
```
|
||||
|
||||
Instantiate OrbitDB and open a new database:
|
||||
Instantiate OrbitDB and create a database:
|
||||
|
||||
```js
|
||||
import { create } from 'ipfs-core'
|
||||
import { OrbitDB } from 'orbit-db'
|
||||
|
||||
const ipfs = await create() // IPFS is required for storage and syncing
|
||||
const ipfs = await create() // IPFS is required for storage and network communication
|
||||
const orbitdb = await OrbitDB({ ipfs })
|
||||
const mydb = await orbitdb.open('mydb')
|
||||
const dbAddress = mydb.address // E.g. /orbitdb/zdpuAuK3BHpS7NvMBivynypqciYCuy2UW77XYBPUYRnLjnw13
|
||||
@example <caption>Open an existing database using its multiformat address:</caption>
|
||||
const mydb = await orbitdb.open(dbAddress)
|
||||
console.log(mydb.address) // /orbitdb/zdpuAuK3BHpS7NvMBivynypqciYCuy2UW77XYBPUYRnLjnw13
|
||||
await mydb.add("hello world!")
|
||||
```
|
||||
|
||||
Use with pre-configured identities:
|
||||
Open and replicate an existing database:
|
||||
|
||||
```js
|
||||
// In another process
|
||||
import { create } from 'ipfs-core'
|
||||
import { OrbitDB, Identities } from 'orbit-db'
|
||||
import CustomStorage from './custom-storage.js'
|
||||
import { OrbitDB } from 'orbit-db'
|
||||
|
||||
const storage = await CustomStorage()
|
||||
const identities = await Identities({ storage })
|
||||
const ipfs = await create() // IPFS is required for storage and syncing
|
||||
const orbitdb = await OrbitDB({ ipfs, identities })
|
||||
const mydb = await orbitdb.open('mydb')
|
||||
const ipfs = await create()
|
||||
const orbitdb = await OrbitDB({ ipfs })
|
||||
const theirdb = await orbitdb.open('/orbitdb/zdpuAuK3BHpS7NvMBivynypqciYCuy2UW77XYBPUYRnLjnw13')
|
||||
for await (let record of theirdb.iterator()) {
|
||||
console.log(record)
|
||||
}
|
||||
```
|
||||
|
||||
Use with existing identities:
|
||||
|
||||
```js
|
||||
import { create } from 'ipfs-core'
|
||||
import { OrbitDB, Identities } from 'orbit-db'
|
||||
|
||||
const identities = await Identities()
|
||||
await identities.createIdentity('userA')
|
||||
|
||||
const ipfs = await create() // IPFS is required for storage and syncing
|
||||
const orbitdb = await OrbitDB({ ipfs, identities, id: 'userA' })
|
||||
const mydb = await orbitdb.open('mydb')
|
||||
```
|
||||
|
||||
See the [OrbitDB module](./module-OrbitDB.html) for more information about how to open databases.
|
||||
See the [OrbitDB module](./module-OrbitDB.html) for more information about how to open databases.
|
||||
|
Loading…
x
Reference in New Issue
Block a user