Flutter return full arrays from Firebase Cloud Firestore

好久不见. 提交于 2021-02-05 06:15:07

问题


LATEST EDIT 2nd Sept:

I am not getting much traction with this, even with a bounty, so I will try and ask a simpler and more specific question.

So I have reorganised the database in line with Doug's suggestions below, as I cannot otherwise reference the arrays in any way in firebase. So now I have a map of arrays, rather than just arrays. Like so:

ObjectsList  >  CarsMap (Map)
                   - sh899873jsa (Array)
                     0  "Toyota"
                     1  "Supra"
                     2  "1996"
                     3  "$4990"

                   - hasd823j399 (Array)
                     0  "Toyota"
                     1  "Corolla"
                     2  "2014"
                     3  "$11990"

                   - nelaoiwi283 (Array)
                     0  "Ford"
                     1  "Territory"
                     2  "2018"
                     3  "$35000"

But I don't know how to actually use this structure, as I have never seen this before. I am getting the first error now with the code provided to me by Frank in his answer below, which I have converted to:

 final DocumentReference documents = await Firestore.instance.collection('ObjectsList');
  DocumentSnapshot snapshot = await documents.get();
  Map<String, dynamic> data = snapshot.data;
  var loadCarItems = [];

  data.forEach((k,v) => {
    values = List<String>.from(v as List<String>),
    print(values),
    if (values[0] == "Toyota") {
      loadCarItems.add(values[0]),
    },
  });

  setState(() {
    CarItemsArray = loadCarItems;
  });

But since I have changed to a map>array structure I am getting an error on this line:

data.forEach((k,v) => {
  values = List<String>.from(v as List<String>),

The error being:

Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'List<String>' in type cast

So clearly I need to change this syntax now the structure has changed, but I have no idea how, and can't find anything online.

Previous Information:

I am trying to work out a way to return whole arrays from Firebase so that I can then process the data inside.

For example, I have a document in the database that contains arrays, like so:

ObjectsList  >  sh899873jsa
                   0  "Toyota"
                   1  "Supra"
                   2  "1996"
                   3  "$4990"

                 hasd823j399
                   0  "Toyota"
                   1  "Corolla"
                   2  "2014"
                   3  "$11990"

                  nelaoiwi283
                   0  "Ford"
                   1  "Territory"
                   2  "2018"
                   3  "$35000"

So for each array, I have generated a random key on creation, which is not important. I basically just need to be able to return all the data as separate objects. Ideally, I would like to be able to return "All Toyotas", for example. That's the end game here.

Here is the code I have generated so far based on suggestions by Frank below who got me onto the right path.

From the build wdiget:

          Container(
            child: StreamBuilder(
              stream: Firestore.instance.collection('cars').document('ObjectsList').snapshots(),
              builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
                if (!snapshot.hasData) {
                  return LoadingAnimationBasic();
                }
                if (snapshot.data == null) {
                  return LoadingAnimationBasic();
                } else {
                  return ListView(
                    shrinkWrap: true,
                    children: _buildListCards(snapshot),
                  );
                }
              },
            ),
          ),

The _buildListCards function, simplified so you can see how it works:

_buildStoresList(AsyncSnapshot<DocumentSnapshot> snapshot) {
return snapshot.data.data.values
    .map((doc) => doc[0] == "Toyota" ? GestureDetector(
  child: Container(
    width: MediaQuery.of(context).size.width,
    child: Card(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(0.0),
      ),
      color: Colors.white70,
      elevation: 10,
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.all(2.0),
            child: ConstrainedBox(
              constraints: BoxConstraints(
                maxWidth: 120,
                minWidth: 120,
                maxHeight: 100,
                minHeight: 100,
              ),
              child: Image.network(
                'some toyota picture URL',
                fit: BoxFit.cover,
              ),
            ),
          ),
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Container(
                width: MediaQuery.of(context).size.width * 0.5,
                child: Padding(
                  padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
                  child: Text(
                    doc[1],
                    style: TextStyle(
                      fontWeight: FontWeight.bold,
                      fontSize: 18,
                    ),
                  ),
                ),
              ),
              Container(
                width: MediaQuery.of(context).size.width * 0.5,
                child: Padding(
                  padding: const EdgeInsets.fromLTRB(5, 10, 0, 0),
                  child: Text(
                    doc[2],
                    style: TextStyle(
                      fontSize: 12,
                    ),
                  ),
                ),
              ),
            ],
          ),
          Column(
            children: <Widget>[
              Padding(
                padding: const EdgeInsets.fromLTRB(5, 40, 0, 0),
                child: Text(
                  doc[3],
                  style: TextStyle(
                    fontSize: 14,
                  ),
                ),
              ),
            ],
          ),
        ],
      ),
    ),
  ),
  onTap: () {
    futureTapHandlerHere();
  },
) : SizedBox(), )
    .toList();
}

So the only thing that remains now is to be able to edit/delete these entries from the database, and I think this has to rely on the unique identifier generated when they are created. I can't see how else to possibly perform this functionality without the identifier, but I don't know how to actually use it, or return it from the database.


回答1:


Calling snapshot.data() returns you a Map<String, dynamic>. You can loop over the entries in this map, and then get the first child of each (array) value.

So something like this:

List.from(event.snapshot.value as List)

final DocumentReference documents = await Firestore.instance.collection('cars').document('ObjectsList');
DocumentSnapshot snapshot = await documents.get();
Map<String, dynamic> data = snapshot.data();
var cars = [];
data.forEach((k,v) => {
  var values = List<String>.from(v as List<dynamic>);
  cars.add(values[0]);
})

setState(() {
  arrayOfCars = cars
});



回答2:


There was no answer to this question. I am still struggling and have lost 11 days of production time on this so far.

Thanks for the suggestions from people trying to help, but this ended up going nowhere and I still have no solved it.




回答3:


This was not solved by doing it in the format listed in the question, and I was trying it this way as another user told me I would not be able to delete individual arrays unless they sat under a map.

The answer here is that the above is not true, and the solution was to ditch the map altogether and just have the arrays. What I did here as it makes sense to me is to have the first object in the array be the unique code, so I can reference it easily, like so:

ObjectsList  >  
(document)      - sh899873jsa (Array)
                 0  "sh899873jsa" 
                 1  "Toyota"
                 2  "Supra"
                 3  "1996"
                 4  "$4990"

               - hasd823j399 (Array)
                 0  "hasd823j399"
                 1  "Toyota"
                 2  "Corolla"
                 3  "2014"
                 4  "$11990"

               - nelaoiwi283 (Array)
                 0  "nelaoiwi283"
                 1  "Ford"
                 2  "Territory"
                 3  "2018"
                 4  "$35000"

These can then be referenced directly and deleted easily:

_deleteMenuItem() async {
  await deleteSelectedImages();
  DocumentReference documentReference = Firestore.instance.collection('data').document('ObjectsList');
  documentReference.updateData({
    CarsMap[selectedItem][0]: FieldValue.delete(),
  });
}

Where CarsMap is the loaded array of car objects at run time, and selectedItem is the item selected in the UI from the ListTiles. So step 1 was to grab all the data from Firebase and populate it into the CarsMap array. Step 2 was to build ListTiles from this array. Step 3 was to have an onTap method that selects the current ListTile, and then store the index of that tile into selectedItem.

This does what I need it to do, and users can now populate and remove arrays from my database as required.



来源:https://stackoverflow.com/questions/63599018/flutter-return-full-arrays-from-firebase-cloud-firestore

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!