问题
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