add
adds a new record and generate a new record keyupdate
update an existing recordput
will either create a new record with a user specified key or update a record
Make sure to use transaction as soon as you perform more than 1 writes. It will greatly improve performances. See information on transaction here
The code below use the Database object db
but the same can be done with a
Store
or Transaction
object
Add some data:
// Use the main store for storing map data with an auto-generated
// int key
var store = intMapStoreFactory.store();
// Add the data and get its new generated key
var key = await store.add(db, {'value': 'test'});
// Retrieve the record
var record = store.record(key);
var readMap = await record.get(db);
expect(readMap, {'value': 'test'});
You can also specify the key of the added record if you don't want to have an auto-generated one. Add will fail if the record already exists.
// Add the data with a specified key (1234).
// Fails if the record already exists
await store.record(1234).add(db, {'value': 'test'});
You can update the data of a given record using put()
or update()
(update()
will fail if the record does not exist):
// Update the record
await record.put(db, {'other_value': 'test2'}, merge: true);
readMap = await record.get(db);
expect(readMap, {'value': 'test', 'other_value': 'test2'});
You can also use put()
with ifNotExists
set to true to only add the record if it does not exist:
await record.put(db, {'value': 'test1'});
// This will not update the record since it already exists
await record.put(db, {'value': 'test2'}, ifNotExists: true);
readMap = await record.get(db);
expect(readMap, {'value': 'test1'});
A record value in an application is typically a map that can be written like this:
// Writing a map
var key = await store.add(db, {
'name': 'Felix',
'age': 4,
'address': {'city': 'Ledignan'}
});
If you want to only update some fields you can use the following semantics
similar to firestore.set
where fields can be deleted, updated and addressed
using the a.b.c
form instead of 'a':{'b':{'c'}}
var record = store.record(key);
// Updating some fields
await record.update(db,
{'color': FieldValue.delete, 'address.city': 'San Francisco'});
expect(await record.get(db), {
'name': 'Felix',
'age': 4,
'address': {'city': 'San Francisco'}
});
Dots (.
) are treated as separator for record.update
calls (not store.add
and record.set
). To allow for keys with dot, you
can escape them using FieldKey.escape
await record.update(db, {FieldKey.escape('my.color'): 'red'});
You can delete a single record by key using the RecordRef.delete
method.
// Record by key.
var record = store.record(key);
// Delete the record.
await record.delete(db);
You can delete one or multiple records using the StoreRef.delete
method.
// Delete all records with a price greater then 10
var filter = Filter.greaterThan('price', 10);
var finder = Finder(filter: filter);
await store.delete(db, finder: finder);
You can also clear the whole store:
// Clear all records from the store
await store.delete(db);
Let's insert/update some data:
// Our shop store sample data
var store = intMapStoreFactory.store('shop');
int lampKey;
int chairKey;
await db.transaction((txn) async {
// Add 2 records
lampKey = await store.add(txn, {'name': 'Lamp', 'price': 10});
chairKey = await store.add(txn, {'name': 'Chair', 'price': 15});
});
// update the price of the lamp record
await store.record(lampKey).update(db, {'price': 12});
updateRecords
is a utility function that can work with or without transaction to update fields in multiple records
// Filter for updating records
var finder = Finder(filter: Filter.greaterThan('name', 'cat'));
// Update without transaction
var store = db.getStore('animals');
await updateRecords(store, {'age': 4}, where: finder);
// Update within transaction
await db.transaction((txn) async {
var store = txn.getStore('animals');
await updateRecords(store, {'age': 5}, where: finder);
});
Let's assume a product store where the unique key is an integer. But you want to have a unique 'code' field (each product having a unique code). (Although as a side note, it is more clever to use the code as a string key)
var store = intMapStoreFactory.store('product');
// Add some data
await db.transaction((txn) async {
await store.add(txn, {'code': '001', 'name': 'Lamp', 'price': 10});
await store.add(txn, {'code': '002', 'name': 'Chair', 'price': 25});
});
Let's write a function that will either add or update a record. To handle race conditions and avoid duplicates, this must be done in a transaction:
/// Either add or modify records with a given 'code'
Future<void> addOrUpdateProduct(Map<String, Object?> map) async {
// Check if the record exists before adding or updating it.
await db.transaction((txn) async {
// Look of existing record
var existing = await store
.query(
finder:
Finder(filter: Filter.equals('code', map['code'])))
.getSnapshot(txn);
if (existing == null) {
// code not found, add
await store.add(txn, map);
} else {
// Update existing
await existing.ref.update(txn, map);
}
});
}
Quick test:
// Update existing
await addOrUpdateProduct(
{'code': '002', 'name': 'Chair', 'price': 35});
// Add new
await addOrUpdateProduct(
{'code': '003', 'name': 'Table', 'price': 82});
// Should print:
// {code: 001, name: Lamp, price: 10}
// {code: 002, name: Chair, price: 35} - Updated
// {code: 003, name: Table, price: 82}
for (var snapshot in await store.query().getSnapshots(db)) {
print(snapshot.value);
}