I'm attempting to post an entire map to Firestore using Flutter as follows:
Profile {
String studentFirstName;
String studentSurname;
String yearLevel;
String preferredHand;
Map<String, dynamic> background = {};
Profile({
this.studentFirstName,
this.studentSurname,
this.yearLevel,
this.preferredHand,
this.background,
)}
Future<bool> createStudent(String schoolId) async {
var newStudent = await db
.collection('schoolStudents')
.doc(schoolId)
.collection('students')
.add({
'studentFirstName': _profile.studentFirstName,
'studentSurname': _profile.studentSurname,
'yearLevel': _profile.yearLevel,
'preferredHand': _profile.preferredHand,
'background': {_profile.background},
}
}
However this fails with the below error message.
Unhandled Exception: Invalid argument: Instance of '_CompactLinkedHashSet<Map<String, dynamic>>'
Can someone let me know if you can post an entire map to Firestore and if not, the most appropriate way to.
As you say,
"Can someone let me know if you can post an entire map to Firestore and if not, the most appropriate way to."
So try this way to post data(example).
Map map=Map();
map ={"name":"abc","id":"1"};
Future<bool> createStudent(String schoolId) async {
var newStudent = await db .collection('schoolStudents') .doc(schoolId)
.collection('students')
.add({
'studentFirstName': _profile.studentFirstName,
'studentSurname': _profile.studentSurname,
'yearLevel': _profile.yearLevel,
'preferredHand': _profile.preferredHand,
'background': map,
}
The problem is that object you would like to add as background filed in Firestore is nested. This is because the background field of the Profile object is already a map from the beginning, so adding brackets ({}) around it in add method is creating Set of Map objects, and Set is not among of Types in Firestore. This is the reason of the error.
So it seems that it's enough to remove brackets ({}) from add method:
Future<bool> createStudent(String schoolId) async {
var newStudent = await db
.collection('schoolStudents')
.doc(schoolId)
.collection('students')
.add({
'studentFirstName': _profile.studentFirstName,
'studentSurname': _profile.studentSurname,
'yearLevel': _profile.yearLevel,
'preferredHand': _profile.preferredHand,
'background': _profile.background,
})
Related
I am using Flutter and I would like to retrieve some data from my realtime database Firebase. I have the following data stored in the my realtime database Firebase:
How can I get each piece of information from it? For example I would like to get the name 'Tom' only?
Reading through firebase documentation you can see that how we read and write data from RTDMS firebase.
static Future<List<PostModel>> getPost() async {
Query postsSnapshot = await FirebaseDatabase.instance
.reference()
.child("posts")
.orderByKey();
print(postsSnapshot); // to debug and see if data is returned
List<PostModel> posts;
Map<dynamic, dynamic> values = postsSnapshot.data.value;
values.forEach((key, values) {
posts.add(values);
});
return posts;
}
your can call this function at the time of build the widget or after any action
FirebaseDatabase.instance.ref("users").onValue.listen((event) {
final data =
Map<String, dynamic>.from(event.snapshot.value as Map,);
data.forEach((key, value) {
log("$value");
});
});
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'm getting the error on the code "snapshot.Data()". This is one of the breaking changes to Firestore, and snapshot is now of type "DocumentSnapshot<Object?>".
BREAKING: Getting a snapshots' data via the data getter is now done via the data() method.
The example supplied in the new documentation wasn't helpful for me.
"The argument type 'Object?' can't be assigned to the parameter type 'Map<String, dynamic>'"
I've tried a number of combinations, but I can't get rid of the error. Also, I'm not using a stream, I just want to read the single record.
Here is the code:
var snapshot = await _reference.doc(_user.uid).get();
return UserData.fromMap(snapshot.data());
Here is the model "fromMap":
factory UserData.fromMap(Map<String, dynamic> map) {
return UserData(
birthday: DateTime.fromMillisecondsSinceEpoch(map['birthday']),
gender: map['gender'],
isDarkMode: map['isDarkMode'],
isMetric: map['isMetric'],
name: map['name'],
password: map['password'],
);
}
Ok, found my issue. I had "_reference" defined like this:
final CollectionReference _reference = FirebaseFirestore.instance.collection('users');
I should have done it this way:
final CollectionReference<Map<String, dynamic>> _reference = FirebaseFirestore.instance.collection('users');
Or just this:
final _reference = FirebaseFirestore.instance.collection('users');
Change it to this:
factory UserData.fromMap(Map<String, dynamic>? map) //added a "?" after dynamic.
This makes your fromMap method accept nullable values, which in theory, your firebase query can return a null if the document doesn't exist.
I tried some code but getting an exception.
The Exception that I'm getting:
java.lang.IllegalArgumentException: Invalid document reference. Document references must have an even number of segments, but Users has 1
I searched for it, according to this, Document references must have an even number of segments like: Collection - document - Collection - document - Collection - document
Query for getting data from firestore:
String getIsNewUSer;
Firestore.instance.collection('Users').document(uid).get().then((DocumentSnapshot document){
print("document_build:$document");
setState(() {
getIsNewUSer=document['IsNewUser'];
print("getIsNewUSe:$getIsNewUSer");
});
});
Query for Updating data to the firestore:
Firestore.instance
.collection('Users')
.document(uid)
.updateData({
"IsNewUser":"1"
}).then((result){
print("new USer true");
}).catchError((onError){
print("onError");
});
These code line at I'm getting above Exception.
initState:
void initState() {
super.initState();
this.uid = '';
FirebaseAuth.instance.currentUser().then((val){
setState(() {
this.uid= val.uid;
print("uid_init: $uid");
});
});
}
Null safe code:
Get data:
var collection = FirebaseFirestore.instance.collection('collection');
var docSnapshot = await collection.doc('doc_id').get();
Map<String, dynamic>? data = docSnapshot.data();
Set data:
var collection = FirebaseFirestore.instance.collection('collection');
collection.add(someData);
Update data:
var collection = FirebaseFirestore.instance.collection('collection');
collection
.doc('foo_id') // <-- Doc ID where data should be updated.
.update(newData);
Delete data:
var collection = FirebaseFirestore.instance.collection('collection');
collection
.doc('some_id') // <-- Doc ID to be deleted.
.delete();
Replace this part in your queries:
Firestore.instance.collection('Users').document(uid)
with
Firestore.instance.document('Users/$uid')
Collection - document - Collection - document - Collection - document
Basically you already had the answer.
It is possible that FirebaseAuth.instance.currentUser() future didn't complete and populte this.uid. So this.uid == '' (empty string). So Firestore is throwing errror as you are trying to updated document at Users which is a collection.
You can validate this by printing this.uid before the update statement.
One way is to use helper method to update
Future<void> update(Map data) async {
final user = await FirebaseAuth.instance.currentUser();
return Firestore.instance.collection('Users').document(user.uid).updateData(data);
}
Then you can use helpr method as update({isNewUser: "1"}).then((r) {...})....
You can follow same approach for fetching the document as well.
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.