Flutter get single variable from a list? - flutter

I am getting data from firestore like this
CollectionReference _collectionRef =
FirebaseFirestore.instance.collection('Users');
QuerySnapshot querySnapshot = await _collectionRef.get();
// Get data from docs and convert map to List
final allData =
querySnapshot.docs.map((doc) => doc.data()).toList();
print(allData);
its printing data in list format like this
I/flutter (13500): [{number: +123131, shopname: ishaq shop, id: here i need doc id , lastupdate: , sendQty: }, {number: +1231231, shopname: ishaq shop, lastupdate: , id: gXVR4Sp3Cm3pii97Gh00, sendQty: }, {number: +123131, shopname: ishaq shop, lastupdate: , id: AM8KL6SxvFkCRQqpTjre, sendQty: }]
I just want to get a number from a list. I try something like
print(allData['number']);
print(allData.number);
but not working for me

Try this. If it works you can iterate it through your list.
You convert your data to list here then try to call like a map. The reason why it is wrong. and replace final with list. It works fine
List allData =
querySnapshot.docs.map((doc) => doc.data()).toList()
Try
print(allData[0]['number']);

allData is a List<Map<String, dynamic>>, it means a list of maps (map: also called dictionary in java/swift and other language).
To Access a single variable you need the index of the dictionary first then use the key to access it.
var number = allData.first['number'];
print(number);
Right here I am printing the first item of the list, but you can access any item you want as long as you have its index.

Related

Flutter how to delete field from firebase array

I am trying to delete a field from my firebase array. I am using this code but it deletes then whole activity array.
FirebaseFirestore.instance
.collection(
widget.user.user.uid)
.doc(documentName)
.update({
"activities":
FieldValue.delete()
Instead I want to delete a specific field from 'activities' like activities[2]. How can I do to fix this?
To remove an item at a specific index you can use the arrayRemove method from FieldValue
FirebaseFirestore.instance.collection(widget.user.user.uid).doc(documentName).update({
"activities": FieldValue.arrayRemove("itemToRemove")
})
You should try using FieldValue.arrayRemove() method and then pass the value that you want to remove using this :
var val=[]; //blank list for add elements which you want to delete
val.add('$addDeletedElements');
FirebaseFirestore.instance
.collection(
widget.user.user.uid)
.doc(documentName)
.update({
"activities":
FieldValue.arrayRemove(val])
You have to tell firebase full path like this
FirebaseFirestore.instance
.collection("chat_dialog")
.doc("India")
.collection("dialog_details")
.where(['firestore_id'].contains('your_value'))
.get()
.then((value) {
print(value.docs.length);
for (var element in value.docs) {
print(element.id);
}
});

Flutter FireStore Create, Read and Update Array with a Map Object

Fairly new to Flutter and FireStore, I'm having trouble finding examples or explanations on how to add Maps to an Array (specifically, Creating the initial Array with a Map, then Reading then Adding more Maps to the collection of the Notes Array).
I have an Event Class for scheduling events and that is working very well. What I'm trying to add is a "Notes" field that would allow an some Administrator to add Notes on one day then come back and add to that Event another set of notes as things change. I don't want to "overwrite" the previous Notes, just keep adding more Notes to the Array of notes.
Specific questions:
How do I Create the "Array" when adding the entry into FireStore using Flutter?
How do I Read the data in the "Array" when it's coming back as a set of "Map fields" in Flutter?
How do I just Add to the Array with a new Note? (I think this needs FieldValue.arrayUnion([someMap]) but I'm not certain as this appears to avoid any overwriting.
The page section here shows writing it out but little else: https://firebase.google.com/docs/firestore/manage-data/add-data#data_types
Below is an example of the FireStore structure I'm trying to create.
Has anyone done this before and do you have some direction you can provide? The Firebase documentation in this space is thin...
To create an new document with array in firestore:
FirebaseFirestore.instance.collection('path/to/collection').add(
{ 'notesArray': [
{'date': 'sometime', 'notes': 'somenotes', 'user': 'someuser'}
]},
SetOptions(merge: true),
);
// or
FirebaseFirestore.instance.collection('path/to/collection').add(
{ 'notesArray': []}, // for an empty array
SetOptions(merge: true),
);
To read the data:
FirebaseFirestore.instance.doc('company').get().then((value) {
final doc = value.data()!;
print(doc['lname']); // should print Gethsemane
print(doc['notesArray'] as List); // should print notes array
final notes = doc['notesArray'] as List;
for (final note in notes) {
print(note['date']);
print(note['notes']);
print(note['user']);
}
// or
for (int i = 0; i < notes.length; i++) {
print(notes[i]['date']);
}
});
Add new data to notes array. Simply use FieldValue.arrayUnion.
E.g
FirebaseFirestore.instance.doc('path/to/doc').set(
{
'notesArray': FieldValue.arrayUnion([
{'date': 'sometime', 'notes': 'somenotes', 'user': 'someuser'}
]),
},
SetOptions(merge: true),
);
// I used set method along with setOptions in order not to
// override other fields (e.g modifiedBy field)
Keep in mind that if your array is going to be very large, it is better to store the notes as a subcollection.
##EDIT##
If you want to update a nested array, you can use the dot notation.
class SchedulerEvents {
final List<Map<String, dynamic>>? notes;
SchedulerEvents({required this.notes});
}
// lets assume we have data like this that we want to update
final data = SchedulerEvents(
notes: [
{'date': 'sometime', 'notes': 'somenotes', 'user': 'someuser'},
],
);
FirebaseFirestore.instance.doc('path/to/doc').set(
{
'schedulerEvents.notes': FieldValue.arrayUnion([data.notes![0]]),
// or
'schedulerEvents.notes': FieldValue.arrayUnion(data.notes![0]),
// 'schedulerEvents.lname: 'test', // to update other fields
},
SetOptions(merge: true),
);
// we used dot notation to update fields here.

Flutter - Can't get collection from firestore

_getLatestCompletedWorkout() async {
try {
QuerySnapshot workouts;
workouts = await FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid)
.collection('workouts')
.get();
for (var workout in workouts.docs) {
print('WORKOUT = ');
print(workout);
}
.....
What I really need is to get the last document saved; but before that I am just trying to fetch the "workouts" collection; the workouts.docs list always has 0 items. There are 2 items in the DB. What is wrong with this code? Also how to get the last saved item?
As mentioned by Frank :
You can refer Alex answer here :
The simplest way to achieve this is to add a date
property to each object in your collection, then simply query it
according to this new property descending and call limit(1) function.
This is the required query:
this.historyRef = afs.collection<History>('history', ref => ref.orderBy('date', 'desc').limit(1));
this.history = this.historyRef.snapshotChanges().map(actions => {
return actions.map(a => {
const data = a.payload.doc.data() as Hisotory;
const docId = a.payload.doc.id;
return { docId, ...data };
});
});
This has been found since cloud_firestore updates that prevent app that not regiter in App Check to take updates seriously "but it store it with lighter id color" which Protect your Cloud Firestore resources from abuse, such as billing fraud or phishing
Kindly check and ensure your app is registered inside App Check in Firebase console

how to write nested array in Firestore using flutter

Building a shopping app I added a cart item in my 'users' collection.
cart stored in
and after the user purchase those item I wanted to store those cart items in other collection 'orders'. but when I tried to store those cart items in my order collection firebase throws Invalid data. Nested arrays are not supported.
what is my mistake here?
Here is my Code
onPressed: (){
//orderItem(cartItem);
getData() async {
return await FirebaseFirestore.instance.collection('users').where('id', isEqualTo: FirebaseAuth.instance.currentUser.uid).get();
}
getData().then((val){
if(val.docs.length>0){
//print(val.docs[0].data()['cart']);
// Map map = val.docs[0].data()['cart'];
var list = [val.docs[0].data()['cart']];
// map.entries.forEach((e) {
// list.add();
// });
// List items = [val.docs[0].data()['cart'].toList()];
FirebaseFirestore.instance.collection('orders').doc().set({
"userId": FirebaseAuth.instance.currentUser.uid,
"userName": FirebaseAuth.instance.currentUser.displayName,
"orders": FieldValue.arrayUnion([[val.docs[0].data()['cart']]]),
"price": cartController.totalCartPrice.value
});
}
else{
print("Not Found");
}
});
},
I think the problem is trivial. You accidentally put list inside list.
"orders": FieldValue.arrayUnion([[val.docs[0].data()['cart']]]),
I think you can skip one pair of [ so you have this:
"orders": FieldValue.arrayUnion([val.docs[0].data()['cart']]),
Also... if val.docs[0].data()['cart'] is a list you'll probably need to skip another pair to this:
"orders": FieldValue.arrayUnion(val.docs[0].data()['cart']),
Arrays in a Firestore documents cannot contain arrays so you cannot have have something like:
[
[orderId: 1, orders: [...orders]],
[orderId: 2, orders: [...orders]],
//This is possible
{orderId: 3, orders: [...orders]}
]
If you try adding a document from the console itself, you'll notice the same.
The best you can do is store the orders as a string, [JSON.stringify(ordersObject)]. Then when you fetch the data back you can parse it into as JSON again..
Second option is restructuring your data, it would have ideal to have a separate collection for orders. Then you can use .where() queries to fetch orders of a specific user. However this'll be more expensive (but ideal) because you will be fetching 12 documents (12 reads) if user has 12 orders.

Flutter: add data to Map (instead of replacing data)

The following transaction completely replaces the data in a Firestore Map when run:
DocumentSnapshot docSnapshot = await tx.get(docRef); // doc Snapshot
if (docSnapshot.exists) {
await tx.update(
docRef,
<String, dynamic>{
'Users': {
'user.uid': {'name': user.displayName, 'date': DateTime.now()},
}
},
);
What would be the correct way to add to a map instead of replacing the existing data, the same way FieldValue.arrayUnion works?
Since you already fetched the data you could take the map out from the snapshot, replace the data there and call the update with the altered map.