firestore_model

Easy way to use firestore collection with data model

Adding Firestore Model to your project

In your project's pubspec.yaml file,

  • Add firestore_model latest version to your dependencies.
# pubspec.yaml

dependencies:
  firestore_model: ^<latest version>

Config

void main() async {
  await FirebaseApp.initializeApp(
      settings: FirestoreModelSettings(
          //persistenceEnabled: true,
          ));
  runApp(MyApp());
}

Data Model

  • define your model User
  • extend model with FirestoreModel with your model Type
class User extends FirestoreModel<User> {
}
  • override toMap && responseBuilder
class User extends FirestoreModel<User> {
  String? firstName;
  String? lastName;

  User({this.firstName, this.lastName});

  // use to read
  User.fromMap(Map<String, dynamic> map) {
    this.firstName = map['first_name'];
    this.lastName = map['last_name'];
  }

  // use to write
  @override
  Map<String, dynamic> get toMap => {
    'first_name': this.firstName,
    'last_name': this.lastName,
  };

  @override
  ResponseBuilder<User> get responseBuilder => (map) => User.fromMap(map);
  
}
  • we plural model name and use it as collection name in this example collection name will be users.
  • if you wont to change collection name override collectionName in your model.
@override
String get collectionName => 'users';

Inject Model

  • Inject your Model
FirestoreModel.inject(User());
  • Inject All your Models
FirestoreModel.injectAll([User()]);
  • retrieve your model
FirestoreModel.use<User>();

Create

To Write in data base:

  • prepare your data model like this:
User user = User(firstName: "Mohamed", lastName: "Abdullah 3");
  • call create method from your model like this:
user.create();
  • return document as a model;
  • if you have id for doc:
user.create(docId: 'hdoihvnoirejiu9345j');

Save

  • use save to create or update model.
  • make changes to your model and call save:
user.firstName = 'new firstname';
user.save()

Update

  • update specific fields in your model call update:
user.update(data: {
"first_name": "Mohamed",
"last_name": "Abdullah"
})
  • update specific model use update by pass docId:
FirestoreModel.use<User>().update(
  docId: 'hdoihvnoirejiu9345j',
  data: {
    "first_name": "Mohamed",
    "last_name": "Abdullah"
  })

delete

  • delete current model call delete:
user.delete();
  • delete specific model use delete by pass docId:
FirestoreModel.use<User>().delete(docId: 'hdoihvnoirejiu9345j')

Exists

  • check if document is exists call exists by docId:
bool isExists = await FirestoreModel.use<User>().exists('hdoihvnoirejiu9345j')

Find

  • To get document data by document id call find:
User user = await FirestoreModel.use<User>().find('hdoihvnoirejiu9345j')
  • To stream document data by document id call streamFind:
Stream<User> streamUser = FirestoreModel.use<User>().streamFind('hdoihvnoirejiu9345j')

All

  • To get all documents call all:
List<User> users = await FirestoreModel.use<User>().all()
  • To stream all documents call streamAll:
Stream<List<User>> streamUsers = FirestoreModel.use<User>().streamAll()

First

  • To get first result from your collection call first:
  • you can build your query like where orderBy or any query buildr methods:
User firstUser = await FirestoreModel.use<User>().first(
    queryBuilder: (query) => query.where('score', isGreaterThan: 100)
    .orderBy('score', descending: true)
    );

Get

  • To get results from your collection call get:
  • you can build your query like where orderBy or any query buildr methods:
List<User> topUsers = await FirestoreModel.use<User>().get(
    queryBuilder: (query) => query.orderBy('score', descending: true).limit(10)
    );
  • To stream results from your collection call streamGet:
Stream<List<User>> topUsers = await FirestoreModel.use<User>().streamGet(
    queryBuilder: (query) => query.orderBy('score', descending: true).limit(10)
    );

Pagination

  • To get results limit and load more as pagination from your collection call paginate.
  • you can build your query like where orderBy or any query buildr methods.
  • you can set perPage in your call or set in your model
List<User> topUsers = await FirestoreModel.use<User>().paginate(
    perPage: 15,
    queryBuilder: (query) => query.orderBy('score', descending: true),
    );
  • To stream results from your collection call streamPaginate:
Stream<List<User>> topUsers = await FirestoreModel.use<User>().streamPaginate(
    perPage: 15,
    queryBuilder: (query) => query.orderBy('score', descending: true),
    );

Builders

  • ModelSingleBuilder: get first or find by docId.
ModelSingleBuilder<User>(
// your query to get first result
query: (q) => q.orderBy('createdAt'),
// pass document id if you need to get only this document
docId: 'iuiouurpoeuriqwe',
builder: (_, snapshot) {
// your widget
});
  • ModelGetBuilder: get documents with any query.
ModelGetBuilder<User>(
// your query to get results
query: (q) => q.orderBy('createdAt'),
builder: (_, snapshot) {
// your list builder
});
  • ModelStreamGetBuilder: stream get documents with any query.
ModelStreamGetBuilder<User>(
// your query to stream results
query: (q) => q.orderBy('createdAt'),
builder: (_, snapshot) {
// your list builder
});
  • ModelStreamSingleBuilder: stream first or find by docId.
ModelStreamSingleBuilder<User>(
// your query to stream first result
query: (q) => q.orderBy('createdAt'),
// pass document id if you need to stream only this document
docId: 'iuiouurpoeuriqwe',
builder: (_, snapshot) {
// your widget
});

Builder Listener

you can listen to any builder: * onLoading => fire when builder is loading. * onChange => fire when your data in stream builder changed. * onSuccess => fire when builder return data * onError => fire if error in query * onEmpty => fire if builder success but data is empty

onChange: () {
  print("Data Change");
},
onLoading: () {
    return Center(
    child: Text("Loading"),
    );
},
onEmpty: () => Center(
  child: Text("Sorry Your List is Empty"),
),
onSuccess: (data) {
  //return builder widget;
},
onError: (error) => print("Error $error"),

FieldValue

  • increment: increment field value
// this increase user score by 1;
user.increment(field: 'score');

// this increase user score by 2;
user.increment(field: 'score', value: 2);
  • decrement: decrement field value
// this decrease user score by 1;
user.decrement(field: 'score');

// this decrease user score by 2;
user.decrement(field: 'score', value: 2);
  • arrayUnion: union elements to array
// append 'kotlin' to user languages
user.arrayUnion(field: 'languages', elements: ['kotlin']);
  • arrayRemove: remove elements from array
// remove 'kotlin' from user languages
user.arrayRemove(field: 'languages', elements: ['kotlin']);
  • remove: remove field from document
// remove 'languages' field from user document
user.remove(field: 'languages');

SubCollection

SubCollection is a collection associated with a specific document.

Prepare SubCollection Model

  • create Model for SubCollection and extends model with SubCollectionModel with your model Type:
class Post extends SubCollectionModel<Post> {
}
  • override toMap && responseBuilder
  • we plural model name and use it as collection name in this example collection name will be posts.
  • if you wont to change subCollection name override subCollectionName in your model
@override
String get subCollectionName => 'posts';

Create in SubCollection

  • use parent to work with subCollection
Post post = user.subCollection<Post>();
post.title = "new test Title For post ${DateTime.now()}";
post.description = "Description Title in post Sub collection";
post.create();

Update document in SubCollection

// use `update` to update document in subCollection
post.update(data: {'title': 'updated title'});

// or you can use `save`
post.description = 'new description';
post.save();

if you have SubCollectionModel you can work as any FirestoreModel

Builder With SubCollection

  • to use builders to retrieve subCollection Documents you must be have parentModel
ModelStreamGetBuilder<Post>(
// parent model for Post SubCollectionModel
parentModel: user,
builder: (_, snapshot) {
// your list builder
}
);

Libraries

firestore_model