简体   繁体   中英

Create a sub collection from a nested list

Ive created a flutter app for keeping recipes.

Every recipe has a list of ingredient.

I create the recipe using a Recipe model and inside i have a list of ingredient.

By default when i save the above Recipe model to Firebase Firestore the Ingredient list is saved as an array.

I plan on expanding the concepts over time and would like to store the ingredient in a sub collection.

I am obviously able to iterate through the questions and add them as a document to their own collection, however this seems messy and likely to cause me problems in the future.

Is there a way in which i can specify that child models are created as a sub collection rather than an array?

Below is what im using currently to write the data

class FirestoreService {
  FirestoreServiceNew._();
  static final instance = FirestoreServiceNew._();

  Future<void> setData({
    @required String path,
    @required Map<String, dynamic> data,
    bool mergeBool = false,
  }) async {
    try {
      final reference = FirebaseFirestore.instance.doc(path);
      print('$path: $data');
      await reference.set(data);
    } catch (e) {
      print('error: $e');
    }
  }

  Future<void> bulkSet({
    @required String path,
    @required List<Map<String, dynamic>> datas,
    bool merge = false,
  }) async {
    final reference = FirebaseFirestore.instance.doc(path);
    final batchSet = FirebaseFirestore.instance.batch();
    print('$path: $datas');
  }

  Future<void> deleteData({@required String path}) async {
    final reference = FirebaseFirestore.instance.doc(path);
    print('delete: $path');
    await reference.delete();
  }

  Stream<List<T>> collectionStream<T>({
    @required String path,
    @required T builder(Map<String, dynamic> data, String documentID),
    Query queryBuilder(Query query),
    int sort(T lhs, T rhs),
  }) {
    Query query = FirebaseFirestore.instance.collection(path);
    if (queryBuilder != null) {
      query = queryBuilder(query);
    }
    final Stream<QuerySnapshot> snapshots = query.snapshots();
    return snapshots.map((snapshot) {
      final result = snapshot.docs
          .map((snapshot) => builder(snapshot.data(), snapshot.id))
          .where((value) => value != null)
          .toList();
      if (sort != null) {
        result.sort(sort);
      }
      return result;
    });
  }

  Stream<List<T>> requestStream<T>({
    @required String path,
    @required T builder(Map<String, dynamic> data, String documentID),
    Query queryBuilder(Query query),
    int sort(T lhs, T rhs),
  }) {
    Query query = FirebaseFirestore.instance.collection(path);
    if (queryBuilder != null) {
      query = queryBuilder(query);
    }
    final Stream<QuerySnapshot> snapshots = query.snapshots();
    return snapshots.map((snapshot) {
      final result = snapshot.docs
          .map((snapshot) => builder(snapshot.data(), snapshot.id))
          .where((value) => value != null)
          .toList();
      if (sort != null) {
        result.sort(sort);
      }
      return result;
    });
  }

  Stream<T> documentStream<T>({
    @required String path,
    @required T builder(Map<String, dynamic> data, String documentID),
  }) {
    final DocumentReference reference = FirebaseFirestore.instance.doc(path);
    final Stream<DocumentSnapshot> snapshots = reference.snapshots();
    return snapshots.map((snapshot) => builder(snapshot.data(), snapshot.id));
  }
}

and my model

class Recipe {
  String id;
  List<Ingredient> ingredients;
  String title;
  String description;
  Timestamp createdOn;

  Recipe(
      {this.id = '',
      this.ingredients,
      this.title,
      this.description,
      this.createdOn});

  Recipe.fromData(Map<String, dynamic> json, String docid) {
    id = docid ?? '';
    title = json['title'];
    description = json['description'];
    createdOn = json['createdOn'];
    if (json['questions'] != null) {
      ingredients= new List<Ingredients>();
      json['ingredients'].forEach((v) {
        questions.add(new Ingredients.fromData(v, null));
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['description'] = this.description;
    data['title'] = this.title;
    data['createdOn'] = this.createdOn;

    if (this.ingredients != null) {
      data['ingredients'] = this.ingredients.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

You can build a path to documents nested in subcollections by alternating calls to collection() and doc() , which return CollectionReference and DocumentReference objects respectively.

FirebaseFirestore.instance
    .collection("top-level-collection")
    .doc("document-id-1")
    .collection("nested-subcollection")
    .doc("document-id-2")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM