When I add to a document using below code I will successfully be able to keep adding additional objects to the array, as long as I stay on the same screen.
void createRecord(dataMap) async {
_user = await FirebaseAuth.instance.currentUser();
var createTransaction = (Transaction tx) async {
var ds = await tx.get(db
.collection('users')
.document(_user.uid)
.collection("days")
.document(DateFormat("yyyy-MM-dd").format(dataMap['day'])));
await tx.set(ds.reference, dataMap);
};
Firestore.instance.runTransaction(createTransaction);
}
After navigating off the screen then back all objects are deleted when trying to add new ones.
When I navigate back from a screen how can I add new objects to the collection with out deleting the old ones?
Thanks.
To add a new, unique item to an array, you can use the arrayUnion operator.
Something like:
await tx.update(ds.reference, {
'breakfast': FieldValue.arrayUnion(dataMap['breakfast'][0])
});
Also see:
how to add or remove item to the the existing array in firestore ?
flutter firestore, add new object in array
How do update array values in Flutter cloud_firestore?
Related
I am very new to Dart, and coding in general. I have produced this code after watching tutorials on YouTube. For the most part, I have been able to troubleshoot most of my problems on my own, here I feel I need some help. I wanted to extract all the fields from a document and use it. I have tried a few codes but there is no proper solution anywhere online.
Here is the code I used to retrieve it:-
documentID = '9zjwixClgwR1Act1OlPK'
firebaseGetData(documentID){
firebaseFirestore.collection('course').doc(documentID).get().then((value) {
print(value.data());
});
}
Here is my database file structure:-
I want to store all the fields in variables and use them. please help me with the correct code, please.
There are two ways to retrieve data stored in Cloud Firestore. Either of these methods can be used with documents, collections of documents, or the results of queries:
Call a method to get the data
const docRef=doc(db,’course’,'9zjwixClgwR1Act1OlPK')
getDoc(docRef)
.then((doc) => {
console.log(doc.data(),doc.id)
})
Set a listener to receive data-change events.
To get real-time data when you set a listener, Cloud Firestore sends your listener an initial snapshot of the data, and then another snapshot each time the document changes.
const docRef=doc(db,’course’,'9zjwixClgwR1Act1OlPK')
onSnapshot(docRef,(doc) => {
console.log(doc.data(),doc.id)
})
For more information, kindly check link1 & link2
Firstly you need to create firestore instance. Your function must be async and return a Future value. Also, you can check this document.
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
Future<Map<String, dynamic>> firebaseGetData({required String documentID}) async {
DocumentSnapshot ds =
await _firestore.collection("course").doc(documentID).get();
Map<String, dynamic> data = ds.data() as Map<String, dynamic>;
print(data["videoDescription"] as String); // check if it null or not
return data;
}
// creating a instance variable
final CollectionReference firestoreInstance =
FirebaseFirestore.instance.collection('course');
void _loadUserData() async {
await firestoreInstance.doc(documentID).get().then((event) {
// you can access the values by
print(event['isDOne']);
print(event['lastViewedOn']);
print(event['lectureNo']);
print(event['videoDescription']);
print(event['videoUrl']);
});
}
call the _loadUserData() function whenever you need to fetch the data.
I have 6 widgets that all share the same data with only one receiving the data from the stream
AllClasses() //displays all of classes and is the start of getting the data from the stream
ClassList(data) //displays nothing but builds the list view and holds the index of what class is to be displayed in classtile widget
ClassTile(data) //presents the data from the index of the data passed in from ClassList
ClassPage(data) //when a classtile is clicked this screen is presented
HomeworksList(data) //goes to this widget when the homeworks button is clicked shows all the homeworks that are available for the specific class clicked on
HomeworkTile(data) // shows the tile for each homework
As you can see I get the data once then pass it down the widget tree multiple times. What has become an issue is that when I am showing the homework list which is 5 widgets down the widget tree from where the data is coming from I have the option to add another homework to the homework list. technically adding it to the firestore database.
The problem is that when I add a Homework it does not refresh the data or rebuild any widgets until I go all the way back to the "AllClasses()" widget.
so to reiterate, I have a widget that shows all of the homeworks and in this widget you are able to add a homework and when you do it updates the subcollection, but does not rebuild the widget that shows all of the homeworks until I go back a couple widgets from where the data is first grabbed
the database schema is set up like this:
Classes {
subcollections:
Homework {
...
}
fields:
}
perhaps its the way I have my database and instead I should have a Homeworks collection that is outside of everything. or maybe its because I am using a generator future to produce the same thing as a stream by using a never ending while loop. either way I don't understand streams enough to understand what to do next, I have been working on this since 8am today and I have tried just about everything in my power. I may just use Homeworks as a seperate collection instead of a subcollection the problem with this is knowing which class I am in when I click on homework.
Stream<List<ClassData>> get fetchClassdata async* {
QuerySnapshot snapshot = await classesCollection.getDocuments();
// while (true) {
List<ClassData> _classList = List<ClassData>();
await Future.forEach(snapshot.documents, (element) async {
QuerySnapshot pre = await Firestore.instance
.collection("Classes")
.document(element.documentID)
.collection("Pre")
.getDocuments();
QuerySnapshot homeworksSnapshot = await Firestore.instance
.collection("Classes")
.document(element.documentID)
.collection("Homework")
.getDocuments();
QuerySnapshot notesSnapshot = await Firestore.instance
.collection("Classes")
.document(element.documentID)
.collection("Notes")
.getDocuments();
QuerySnapshot testsSnapshot = await Firestore.instance
.collection("Classes")
.document(element.documentID)
.collection("Tests")
.getDocuments();
List<Preq> _preList = List<Preq>();
List<Homework> _homeworkList = List<Homework>();
List<Note> _notesList = List<Note>();
List<Test> _testsList = List<Test>();
pre.documents.forEach((preClass) {
Preq preqData = Preq.fromMap(preClass.data);
if (preClass.data != null) {
_preList.add(preqData);
}
});
homeworksSnapshot.documents.forEach((hwork) {
Homework homeworkdata = Homework.fromMap(hwork.data);
_homeworkList.add(homeworkdata);
});
ClassData data = ClassData.fromMap(
element.data, element.documentID, _preList, _homeworkList);
if (data != null) {
_classList.add(data);
}
});
yield _classList;
// }
}
}
I am in a situation where when a users makes a payment, his cart products Stored in Firestore collection (CartProducts) should be moved to new collection Called SuccessFullOrders .
So my Basic Question is how to move all documents from one collection to Firestore other Collection in Flutter
I don't Know how to write code for this in flutter.Thanks for your Answers
Here's my Code
void _onPressed()async {
final FirebaseAuth _auth = FirebaseAuth.instance;
FirebaseUser user = await _auth.currentUser();
print(user.uid);
firestorInstance.collection("users").getDocuments().then((querySnapshot) {
querySnapshot.documents.forEach((result) {
firestorInstance.collection("users").document(user.uid).collection("CartProducts").getDocuments().then((querySnapshot) {
querySnapshot.documents.forEach((result) {
//what to write here so that new documents would be created in other collection
print(result.data);
});
});
});
});
}
Currently there's no way to copy a collection into another provided by firebase officially. And, for sure, you can iterate over your previous collection & create new documents in the other.
In your case you should be doing something like:
userFirebaseInstance
.collection(NewCollection)
.document()
.setData(YourDataHere)
I have a Firebase Firestore database as you can see in the picture. I'd like to get every document from the questions collection with their fields.
I found the following solution on the internet:
//in this list we store the data
List adatok = [];
Future<void> getData(){
databaseReference.getDocuments().then((QuerySnapshot snapshot) {
snapshot.documents.forEach((f){
data = f.data;
adatok.add(data);
print(adatok.length);
print(adatok);
}
);
}
);
}
My problem is that when I call this function (in an onPresed() function of a button), for the first time of pressing the adatok list is empty. But when I press the button for the second time, it contains every data which I wanted to acquire.
Did I do something wrong? Is there another way to get the data?
The layout of the database
Use the code below:
List adatok = [];
Future<void> getData() async{
QuerySnapshot snapshot = await databaseReference.getDocuments();
snapshot.documents.forEach((f){
data = f.data;
adatok.add(data);
print(adatok.length);
print(adatok);
}
}
By this way, The program waits until it gets all the documents.
and then adds it to your snapshots.
Also you have to change your onPressed() function to async/await like the following:
onPressed:() async{
await getData();
/...
}
So the program waits until getData() finishes.
I want to remove (or change) one specific object in an object list of one Firestore document.
Is there a way to tx.update(ref,objectlist.element) directly?
Right now, I get the document snapshot, I read the object list, modify it, then tx.update the whole objectlist.
Firestore.instance.runTransaction((Transaction tx) async {
DocumentSnapshot postSnapshot = await tx.get(postRef);
if (postSnapshot.exists) {
Map<String, dynamic> myMap = Map.from(postSnapshot.data["objList"]);
myMap.remove(something);
await tx.update(postRef, <String, dynamic>{"objList": myMap}).then((x) {
print("leaving document editor");
_goBackToMain();
});
}
});
While that works, I'm worried about conflicts if two users try to update the same objectlist at the same time.