How to add new data to firebase - flutter

How to add new data to firebase, in the picture on the second column there are users, and on the last one there is my note. This note whas created when user created account, and it whas updated when user logged in, before whas "bad location" etc. My problem is to add new note like this, not update it, kepp it, and at the same time, in the same column have some kind of "new collection" with the same 3 strings, but with different data.
class DataService {
final String uid;
DataService({required this.uid});
final CollectionReference notesCollection =
FirebaseFirestore.instance.collection('Notes');
Future createUserData(String notes, String localisation, String title) async {
return await notesCollection.doc(uid).set({
'notes': notes,
'title': title,
'localisation': localisation,
});
}
Future addData(String notes, String localisation, String title) async {
return await notesCollection.doc(uid).set({
'notes': notes,
'title': title,
'localisation': localisation,
});
}
}
This class shows my createUserData, when my user creates account or loggs in, but how to change "addData" in order to have logic as I described above?

if I understand correctly you want to create a new collection for each documents as history. try this:
notesCollection.doc(uid).collection("historic").add({
'notes': notes,
'title': title,
'localisation': localisation,});

Related

How to make a WishedProduct Widget using FirebaseFirestore

I'm making a product display app.
I'm going to create a "Wish List" widget that brings up the product that the user picked as 'wish item'.
I structured it as shown in picture 1.
And to create a widget,
I get all the documents of the collection('wish') of doc('User A').
And with their String values(product name) of the doc,
Get the product data from the collection ('Product') using Query.
The product collection is shown in the picture below.
Is there a more efficient way?
I thought it might be easier to change the data structure.
However, even if I create a new Collection('Wish'), at the same level as Collection('Product'), and put the product's name and user's e-mail in it,
I need to focus on the 'Product' collection with the 'Product name'.
Because I have to use the price, brand, name of product, in Collection('Product').
Is there any other efficient way I'm missing? Thank you!
Instead of storing the product name in string you can use reference type to store direct reference of the document inside other document.
Example code
DocumentReference ref = db.collection('products').doc('product-document-id');
Map<String,dynamic> data = {
'name' : 'Product A',
'product_ref' : ref, // Product document Reference
};
db.collection("users")
.doc("user-id")
.collection("wish")
.doc("your_product_name")
.set(data);
This will add the wish product with dynamic id.
Now you can directly read the document using the product_ref. You can use something like this
final docRef = db.collection("users")
.doc("user-id")
.collection("wish").doc("your_product_name");
final docSnapshot = await docRef.get();
if (docSnapshot.exists) {
final data = doc.data() as Map<String, dynamic>;
var productRef = data?['product_ref'];
productRef.get().then((DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists) {
// you will get your product here
}
});
}

The operator '[]' isn't defined for the type 'Object'.Getting data from one collection and adding it to another

In my firestore, i have a creators collection created and i am trying to create an edit profile collection. i want to get the value of a field in the creators collection and add it to the edit profile collection. After some research, i found out a way to go about doing this but when i want to set the value to the field, i get the error above. I would really appreciate some help.
here is the code
editProfile()async{
CollectionReference creatorCollection = FirebaseFirestore.instance.collection('Creators');
CollectionReference editProfileCollection = FirebaseFirestore.instance.collection('EditProfile');
String profileImageUrl =await uploadProfilePictureToStorage(_image);
String profilePicUrl =await uploadProfilePictureToStorage(_profilePic);
creatorCollection.where("fullName", isEqualTo: widget.enterName).get().then((querySnapshot) {
querySnapshot.docs.forEach((result) {
final DocumentSnapshot creatorDoc = result;
editProfileCollection.doc(FirebaseAuth.instance.currentUser!.uid).set({
'FullName': creatorDoc.data()?["fullName"],
'EditedFullName': _name,
'location': _location,
'links': _linked,
'contact':_contact,
'dob':_dob,
'uid':FirebaseAuth.instance.currentUser!.uid,
'likes':[],
'Headers': profileImageUrl,
'ProfilePic':profilePicUrl
}).whenComplete((){
Navigator.pop(context);
});
});
});
what i am trying to get from the creators collection is the fullname. If there is a better way to go about getting the value, that would also be appreciated. Here is the collection by the way
You can use .get or use as Map? like 'FullName': (creatorDoc.data() as Map?)?["fullName"],
'FullName': creatorDoc.get("fullName"),

How to store default userName, themeMode and themeColor to Cloud Firestore after creating new user in Flutter?

When a new user is created in Firebase, I want to create a collection of user preferences and save it to Cloud Firestore as well. All defaulted to username String 'John Doe', thememode ThemeMode.light and themecolor FlexScheme.money (using flexcolorscheme package).
I can store Strings and int's (works fine with my code), but not ThemeModes apparently and I don't know how to solve this correctly.
I created a PrefService class:
class PrefService {
//Declare a nullable String to hold user unique ID
final String? uid;
//When we call PrefService, require to insert user unique ID
PrefService({this.uid});
final CollectionReference<Object?> userPreferences =
FirebaseFirestore.instance.collection('userPreferences');
Future<dynamic> updateUserPreferences(
String name,
ThemeMode themeMode,
FlexScheme themeColor,
) async {
//If document doesn't exist yet in Firebase, it will be created under user unique ID
return userPreferences.doc(uid).set(<String, dynamic>{
'name': name,
'themeMode': themeMode,
'themeColor': themeColor,
});
}
}
And an AuthService class:
class AuthService {
//Sign UP user only with email and password
Future<void> signUp({
required String email,
required String password,
required BuildContext context,
}) async {
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: email,
password: password,
);
//After creating a user, create a database file under user unique ID as well
//Store default name, themeMode and themeColor, which can be adjusted later by user.
Logger().i('Database record created for user');
await PrefService(uid: FirebaseAuth.instance.currentUser!.uid)
.updateUserPreferences(
'John Doe',
ThemeMode.light,
FlexScheme.money,
);
etc...
When I set all parameters of updateUserPreferences() to type String, everything works and I get a nice collection under a unique user ID. But it does not let me store parameter of type ThemeMode:
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Invalid argument: Instance of 'ThemeMode'
Why can I store a String, but not a ThemeMode? I want users to be able to change these settings in a SettingsScreen(), but how should I store them correctly?
I am aware of the existence of SharedPreferences, but I want to do it this way. If anyone can show me how (and why) I should handle this, it would be greatly appreciated.
Objects cannot be saved in firebase directly. If it is Model you can store it in map format.
In your case shore the them mode as String or int i.e. 0 for light and 1 for dark and convert it when you read the data.

Linking Firebase Authenticated user with 'users' collection in Flutter

New to flutter, and first post here!
I am building a mobile app with flutter, using Firebase and Cloud Firestore. Each user, when authenticated (by email and password), is also currently then added to a 'users' collection in Firestore - like this:
sign up method:
Future signUp() async {
if (passwordConfirmed()) {
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: _emailController.text.trim(),
password: _passwordController.text.trim(),
);
// add user details
addUserDetails(
_firstNameController.text.trim(),
_lastNameController.text.trim(),
_emailController.text.trim(),
_baseStationController.text.trim(),
);
}
}
Future addUserDetails(String firstName, String lastName, String email,
String baseStation) async {
await FirebaseFirestore.instance.collection('users').add({
'first name': firstName,
'last name': lastName,
'email': email,
'base station': baseStation,
});
}
The signup() method is called when they input their information into text fields within a form, and click a button. This works successfully, and my user collection receives the data, and sign in/out works as it should.
Those users have a 'base station' (which is stored as a field within that users document in Firestore) which is their place of work. I want to show a welcome screen when they log in, so that the current users 'base station' is displayed.
I can access their email address using:
final thisUser = FirebaseAuth.instance.currentUser!;
and then for example to show this when they log in:
Text('Hello, ${thisUser.email!}')
this works no problem, however...
I can't work out how their authentication then links to the collection, so I want to show the 'base station' for the 'currentUser' for example when they log in (I don't want them to have to select their base station every time from a picker when they've already provided the information on sign up.
As an aside - I can also (separately) successfully read the data from the collection and (for example) create a listView builder with the users collection information, but this is for all users, and not specifically the 'currentUser' that is logged in.
All help gratefully received, apologies if I have missed anything.
update addUserDetails as follows
Future addUserDetails(String firstName, String lastName, String email,
String baseStation) async {
await FirebaseFirestore.instance.collection('users').doc(FirebaseAuth.instance.currentUser!.uid).set({
'first name': firstName,
'last name': lastName,
'email': email,
'base station': baseStation,
});
if you then want to get specific user detail then use the code as follows
final user = await FirebaseFirestore.instance.collection('users').doc(FirebaseAuth.instance.currentUser!.uid).get();

Add subcollection of comments to desired post

So my comments are getting added to the correct post when the comment is made by the author on their own post, like so
The Firestore code updated test:
Future<String> postComment(String postId, String text, String authorId,
String name, String profilePic) async {
String res = 'Some Error occurred';
try {
if (text.isNotEmpty) {
String commentId = const Uuid().v1();
await FirebaseFirestore.instance
.collection('posts')
.doc(authorId)
.collection('userPosts')
.doc(postId)
.collection('comments')
.doc(commentId)
.set({
'profilePic': profilePic,
'name': name,
'uid': authorId,
'text': text,
'commentId': commentId,
'datePublished': DateTime.now()
});
res = 'success';
}
} catch (e) {
res = e.toString();
}
return res;
}
The desired structure of how the comments should get added: posts>UID(of poster)> userPosts(List of their posts)>postID>append comment to this postId as a subcollection.
Now, when I try to create a comment on a post made by another user, a new collection gets started with the ID of the post as its collection name. The postId it gets is the CORRECT id, however, the actual comment itself doesn't get added to the collection of THAT post. As you can see from the circle in the second image, the IDs match, however, the comment made doesn't go where it's intended, as it does in the first image. Does anyone know how I can fix this?
Image with new code test, new collection gets made with the UID of the person who's post I am commenting on, doesn't get added to the subcollection of the actual postId
When you're using the following reference:
await FirebaseFirestore.instance
.collection('posts')
.doc(uid)
.collection('userPosts')
.doc(postId)
.collection('comments')
.doc(commentId)
You're always trying to add data inside a document that corresponds to the currently authenticated user. That's the reason why when you are using the above code with another user, it writes the data to another location. Which location, the one that corresponds to that user.
If you want to write the data under a particular location, you have to create a reference that points to that particular location. For instance, if you want a user to write some data, in a document that corresponds to another user, you have to create a reference that contains that UID. That can be simply done, by adding the ID of the user who creates the post inside the document. In that way, doesn't matter which user reads the post, when you want to write the data, you can use the ID of the user who created the post, to construct the correct path.