【问题标题】:How to upload multiple urls on single Firestore document? Flutter/Dart如何在单个 Firestore 文档上上传多个网址?颤振/飞镖
【发布时间】:2021-11-20 22:44:16
【问题描述】:

目前,我可以在 FirebaseStorage 中保存上传文件中的单个 url。 问题是当我有多个选择的文件 url 时,FirebaseFirestore 为 FirebaseStorage 上的每个上传文件创建多个具有不同 url 的文档。 我如何才能在 FirebaseFirestore 单个文档中添加所有选择的文件 url(如 List (url1: fileurl1, url2: fileurl2 ....)? 这是我的代码,谢谢!

import 'package:file_picker/file_picker.dart';
import 'package:firebase_storage/firebase_storage.dart' as firebase_storage;
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:io';

class MobilePortraitFields extends StatefulWidget {
  const MobilePortraitFields({Key? key}) : super(key: key);

  @override
  _MobilePortraitFieldsState createState() =>
      _MobilePortraitFieldsState();
}

class _MobilePortraitFieldsState
    extends State<MobilePortraitFields> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(child: _Body111()),
    );
  }
}

class _Body111 extends StatefulWidget {
  @override
  __Body111State createState() => __Body111State();
}

class __Body111State extends State<_Body111> {
  final firebase_storage.FirebaseStorage _firebaseStorage = firebase_storage.FirebaseStorage.instance;

  final TextEditingController descriptionController = TextEditingController();
  final GlobalKey<FormState> _formKeyValue = GlobalKey<FormState>();
  List<firebase_storage.UploadTask> uploadedTasks = [];
  List<File> selectedFiles = [];

Future selectFiles() async {
    try {
      FilePickerResult? result = await FilePicker.platform
          .pickFiles(allowMultiple: true, allowCompression: true);

      if (result != null) {
        selectedFiles.clear();
        for (var selectedFile in result.files) {
          File file = File(selectedFile.path ?? '');
          selectedFiles.add(file);
        }

      } else {
        // ignore: avoid_print
        print("User has cancelled the selection");
      }
    } catch (e) {
      // ignore: avoid_print
      print(e);
    }
  }

uploadFilesToStorage(File file) {
    firebase_storage.UploadTask task = _firebaseStorage
        .ref()
        .child("files/${DateTime.now().toString()}")
        .putFile(file);
    return task;
  }

saveFilesUrlToFireStore(firebase_storage.UploadTask task) {
    task.snapshotEvents.listen((snapShot) {
      if (snapShot.state == firebase_storage.TaskState.success) {
        snapShot.ref.getDownloadURL().then((value) => writeFilesUrlToFireStore(value));
      }
    });
  }


writeFilesUrlToFireStore(value) {
   Map<String, dynamic> issuesData = {
     "description": descriptionController.text,
     "location": 'Texas, USA',
     "urls": value,
   };

   CollectionReference collectionReference =
   FirebaseFirestore.instance.collection('issues');
   collectionReference.add(issuesData);
  }

addData() {
//Create button to add all in one document
    if (_formKeyValue.currentState!.validate()) {
      for (var file in selectedFiles) {
        final firebase_storage.UploadTask task = uploadFilesToStorage(file);
        saveFilesUrlToFireStore(task);

        setState(() {
          uploadedTasks.add(task);
        });
      }

      ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('Was created successfully')));
      Navigator.pop(context);
    }
  }

  Widget _description() {
    return Padding(
      padding: const EdgeInsets.fromLTRB(0, 35, 0, 0),
      child: Container(
        decoration: const BoxDecoration(
          borderRadius:
          BorderRadius.all(Radius.circular(20)),
          color: Colors.white,
          boxShadow: [
            BoxShadow(
              color: Colors.grey,
              spreadRadius: 2,
              blurRadius: 2,
              offset: Offset(5, 5), // changes position of shadow
            ),
          ],
        ),
        child: TextFormField(
          controller: descriptionController,
          decoration: InputDecoration(
            hintText: 'Here you can describe ...',
            border: OutlineInputBorder(borderRadius: BorderRadius.circular(20.0),borderSide: const BorderSide(color: Colors.grey),),
          ),
          validator: (String? value) {
            if (value!.isEmpty) {
              return "Please provide description";
            } else {
              return null;
            }
          },
          maxLines: 8,
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        FocusScope.of(context).unfocus();
      },
      child: Form(
        autovalidateMode: AutovalidateMode.always,
        key: _formKeyValue,
        child: Column(
          children: [
ListView(
shrinkWrap: true,
              reverse: true,
              padding: const EdgeInsets.symmetric(horizontal: 15.0),
              children: <Widget>[
                _description(),
const Padding(padding: EdgeInsets.fromLTRB(0, 10, 10, 0)),
                ElevatedButton(
                  style: ButtonStyle(
                      padding: MaterialStateProperty.all(const EdgeInsets.all(0)),
                      shape: MaterialStateProperty.all<RoundedRectangleBorder>(
                          RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(20.0),
                          )
                      ),
                      backgroundColor: MaterialStateProperty.all<Color>(Colors.transparent),
                      shadowColor: MaterialStateProperty.all<Color>(Colors.transparent)),
                  onPressed: addData,
                  child: Ink(
                    decoration: const BoxDecoration(
                      borderRadius:
                      BorderRadius.all(Radius.circular(20)),
                      gradient: LinearGradient(
                        colors: [Color(0xFF21d39b), Color(0xFF0ac4ba)],
                        begin: Alignment.centerLeft,
                        end: Alignment.centerRight,
                      ),
                    ),
                    child: Container(
                      decoration: const BoxDecoration(
                        borderRadius:
                        BorderRadius.all(Radius.circular(20)),
                      ),
                      constraints: const BoxConstraints(minWidth: 120, minHeight: 40),
                      alignment: Alignment.center,
                      child: const Center(
                        child: Text(
                          "Create",
                          textAlign: TextAlign.center,
                          style: TextStyle(
                            color: Colors.white,
                            fontSize: 20,
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
 ].reversed.toList(),
),
],
        ),
      ),
);
  }
}

编辑:代码已更新。

【问题讨论】:

  • 每次调用collectionReference.add(...) 都会创建一个新文档。如果您想要一个包含多个文件的文档,则需要确保在所有文件都已完全上传后只调用一次collectionReference.add(...)
  • 这并没有多大帮助。我已经将它们都更改为异步函数并放入等待,但我仍然有多个文档,它们之间只有区别,来自 FirebaseStorage 的 url。

标签: flutter dart google-cloud-firestore firebase-storage


【解决方案1】:

正如弗兰克所说,您只需调用一次 add 方法,我想为它添加更多简单性。

因此,在致电collectionReference.add(...) 之前,请务必上传所有图片。获得图像列表后,您可以将它们作为值(数组)添加到 firestore 中。

Firestore 允许您将值存储在多种数据类型中。最适合添加的数据类型是 ArrayMap

有关 firebase 中数据类型的更多信息,请查看:https://firebase.google.com/docs/firestore/manage-data/data-types

【讨论】:

  • 谢谢,但我没有设法自己将其更改为 Array。
  • 在 Firestore 文档中设置数据时,您必须执行类似 collectionReference.doc().set({key: value}) 的操作。这样做时,只需将字符串(url)数组传递给值
猜你喜欢
  • 1970-01-01
  • 2020-04-04
  • 2020-01-12
  • 2021-11-20
  • 2020-11-05
  • 1970-01-01
  • 1970-01-01
  • 2020-08-12
相关资源
最近更新 更多