Usage Examples
Open a Database
Every Database
has a name which is used to determine its filename. The
full filename is the concatenation of the database name and the extension
.cblite2
.
When opening a database without specifying a directory it will be put into a default location that is platform dependent:
final db = await Database.openAsync('my-database');
If you want to open a database in a specific directory you can specify the directory like this:
final db = await Database.openAsync(
'my-database',
DatabaseConfiguration(directory: 'my-directory')
);
If a database with the same name already exists in the directory, it will be opened. Otherwise a new database will be created.
When you are done with the database, you should close it by calling
Database.close
. This will free up any resources used by the database, as
well as remove change listeners, close change streams and close associated
replicators.
Access a Collection
Documents live in collections.
Existing collections can be accessed through Database.collection
:
final collectionInDefaultScope = await database.collection('my-collection');
final collectionInCustomScope = await database.collection('my-collection', 'my-scope');
The default collection is always available and can be accessed through
Database.defaultCollection
:
final defaultCollection = await database.defaultCollection;
Create a Collection
To create a collection, call Database.createCollection
:
final collectionInDefaultScope = await database.createCollection('my-collection');
final collectionInCustomScope = await database.createCollection('my-collection', 'my-scope');
If the collection already exists, it will be returned. Otherwise a new collection will be created.
Create a Document
The default constructor of MutableDocument
creates a document with a
randomly generated id and optionally initializes it with some properties:
final doc = MutableDocument({
'name': 'Alice',
'age': 29,
});
await collection.saveDocument(doc);
It's also possible to create a document with a specific id:
final doc = MutableDocument.withId('ali', {
'name': 'Alice',
'age': 29,
});
await collection.saveDocument(doc);
Read a Document
To read a Document
pass the document's id to Collection.document
:
final doc = await collection.document('ali');
// If the document exists, an immutable `Document` is returned.
if (doc != null) {
print('Name: ${doc.string('name')}');
print('Age: ${doc.string('age')}');
}
Update a Document
To update a document, first read it, turn it into a MutableDocument
and
update its properties. Then save it again with Collection.saveDocument
:
final doc = await collection.document('ali');
final mutableDoc = doc!.toMutable();
// You can use one of the typed setters to update the document's properties.
mutableDoc.setArray(MutableArray(['Dart']), key: 'languages');
// Or alternatively, use this subscript syntax to get a [MutableFragment] and
// use it to update the document.
mutableDoc['languages'].array = MutableArray(['Dart']);
// The untyped `setValue` setter does the conversion from a plain Dart collection
// to a document collection (`MutableArray` or `MutableDictionary`) for you.
mutableDoc.setValue(['Dart'], key: 'languages');
// Again, there is an alternative subscript syntax available.
mutableDoc['languages'].value = ['Dart'];
await collection.saveDocument(mutableDoc);
Check out the documentation for Collection.saveDocument
to learn about how
conflicts are handled.
Delete a Document
To delete a document, you need to read it first and than pass it to
Collection.deleteDocument
:
final doc = await collection.document('ali');
await collection.deleteDocument(doc);
Check out the documentation for Collection.deleteDocument
to learn about
how conflicts are handled.
Build a Query
With the QueryBuilder
API
A Query
can be built in a type safe way through the QueryBuilder
API.
The query below returns the average age of people with the same name:
final query = const QueryBuilder()
.select(
SelectResult.property('name'),
SelectResult.expression(
Function_.avg(Expression.property('age'))
).as('avgAge'),
)
.from(DataSource.collection(collection))
.groupBy(Expression.property('name'));
final resultSet = await query.execute();
final results = await resultSet
.asStream()
// Converts each result into a `Map`, consisting only of plain Dart values.
.map((result) => result.toPlainMap())
.toList();
print(results);
Given these documents:
[
{'name': 'Alice', 'age': 29},
{'name': 'Bob', 'age': 45},
{'name': 'Alice', 'age': 16},
]
results
will be:
[
{'name': 'Alice', 'avgAge': 22.5},
{'name': 'Bob', 'avgAge': 45},
]
Build a Query
With SQL++
SQL++ is an extension of SQL for querying JSON style data.
The query below is equivalent to query from the QueryBuilder
example
above:
final query = await db.createQuery(
'''
SELECT name, avg(age) AS avgAge
FROM users
GROUP BY name
''',
);
Data Sync With Replicator
To Sync Gateway
This example synchronizes the database with a remote Sync Gateway instance,
without authentication. This only works when Sync Gateway has been configured
with the GUEST
user.
A ReplicatorConfiguration
with only default values creates a
Replicator
with type
ReplicatorType.pushAndPull
that is
not continuous
. You need add the Collection
s that you want to replicate
to the configuration.
After starting this replicator, it will push changes from the local database to the remote database and pull changes from the remote database to the local database and then stop again.
Both Replicator.start
and Replicator.stop
don't immediately
start/stop the replicator. The current status of the replicator is available in
ReplicatorStatus.activity
.
final config = ReplicatorConfiguration(target: UrlEndpoint('http://localhost:4984/my-database'))
..addCollection(collection);
final replicator = await Replicator.create(config);
await replicator.addChangeListener((change) {
print('Replicator activity: ${change.status.activity}');
});
await replicator.start();
When you are done with the replicator, you should close it by calling close
.
This will free up any resources used by the replicator, as well as remove change
listeners and close change streams.