I need to make the users UID the same as the documents id.
ex:
In [Authentication], I have the user with the following info: email: [email protected] UID: U8EZAjrCWQRvll6CVmI6OpGZwcH3
In [Firestore database], I have a user collection. In the user collection, I have a document for each user.
I would like to have the document id be the same as the user id.
is this possible?
Below is the snip I have for creating users in [Authentication] and [Firestore database] user collection::
class FirebaseAuthProvider implements AuthProvider {
@override
Future<void> initialize() async {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
}
@override
Future<AuthUser> createUser({
required String email,
required String password,
}) async {
try {
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: email,
password: password,
);
final user = currentUser;
if (user != null) {
return user;
} else {
throw UserNotLoggedInAuthException();
}
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
throw WeakPasswordAuthException();
} else if (e.code == 'email-already-in-use') {
throw EmailAlreadyInUseAuthException();
} else if (e.code == 'invalid-email') {
throw InvalidEmailAuthException();
} else {
throw GenericAuthException();
}
} catch (_) {
throw GenericAuthException();
}
}
}
Below is my FirebaseCloudStorage class
class FirebaseCloudStorage {
final user = FirebaseFirestore.instance.collection('user');
Future<CloudUser> createNewUser({
required String userId,
required String userState,
required String userImage,
required String userFirstName,
required String userLastName,
required String userCellNumber,
required String userCity,
required String userAreaCode,
required String userAddress,
required String userEmail,
}) async {
final document = await user.add({
userIdColumn: userId,
userStateColumn: userState,
userImageColumn: userImage,
userFirstNameColumn: userFirstName,
userLastNameColumn: userLastName,
userCellNumberColumn: userCellNumber,
userCityColumn: userCity,
userAreaCodeColumn: userAreaCode,
userAddressColumn: userAddress,
userEmailColumn: userEmail,
});
final fetchedUser = await document.get();
return CloudUser(
documentId: fetchedUser.id,
userId: userId,
userState: userState,
userImage: userImage,
userFirstName: userFirstName,
userLastName: userLastName,
userCellNumber: userCellNumber,
userCity: userCity,
userAreaCode: userAreaCode,
userAddress: userAddress,
userEmail: userEmail,
);
}
// singleton
static final FirebaseCloudStorage _shared =
FirebaseCloudStorage._sharedInstance();
FirebaseCloudStorage._sharedInstance();
factory FirebaseCloudStorage() => _shared;
}
Below is the sign up screen button that kicks off all the creation
Future createUserAccount() async {
if (_photo == null) return;
try {
setState(() {
_isLoading = true;
});
await AuthService.firebase().createUser(
email: _email.text,
password: _password.text,
// displayName: _userFirstName.text, // not working
);
final userId = AuthService.firebase().currentUser?.id;
final destination = 'user-profile-image/$userId';
final ref = FirebaseStorage.instance.ref(destination);
await ref.putFile(_photo!);
imageUrl = await ref.getDownloadURL();
_userService.createNewUser(
userId: userId as String,
userState: 'new',
userImage: imageUrl as String,
userFirstName: _userFirstName.text,
userLastName: _userLastName.text,
userCellNumber: _userCellphoneNumber.text,
userCity: _userCity.text,
userAreaCode: _userAreaCode.text,
userAddress: _userAddress.text,
userEmail: _email.text,
);
setState(() {
_isLoading = false;
});
AuthService.firebase().sendEmailVerification();
Navigator.of(context).pushNamed(verifyEmailRoute);
} on WeakPasswordAuthException {
await showErrorDialog(
context,
'Weak password',
);
} on EmailAlreadyInUseAuthException {
await showErrorDialog(
context,
'Email is already in use',
);
} on InvalidEmailAuthException {
await showErrorDialog(
context,
'This is an invalid email address',
);
} on GenericAuthException {
await showErrorDialog(
context,
'Failed to register',
);
}
}
CodePudding user response:
You can use a custom id for a document by using set
instead of add
and specifying the already existing user identifier. So in your createNewUser
function you can do it like:
final document = await user.doc(userId).set({
userIdColumn: userId,
userStateColumn: userState,
userImageColumn: userImage,
userFirstNameColumn: userFirstName,
userLastNameColumn: userLastName,
userCellNumberColumn: userCellNumber,
userCityColumn: userCity,
userAreaCodeColumn: userAreaCode,
userAddressColumn: userAddress,
userEmailColumn: userEmail,
});
Note: It might be a better solution to maintain your own user collection from a trusted environment on the server side and not from the client. For example you can use Firebase Authentication triggers to add / delete / modify user data whenever there is a change, for example a new user is signed up. This way you don't have to allow write operations to your user collection from the client.
CodePudding user response:
You can use an onCreate trigger on an authentication event.
If you are using cloud functions you can use the following code to create a new document in your user collection when a new authentication entry is created:
export const createUser = functions.auth
.user()
.onCreate(async (user) => {
// DataObject includes all the data, which should be stored in firestore
const dataObject = {
email: user.email,
};
await dbFirestore
.collection('users')
.doc(user.uid)
.set(dataObject, {merge: true});
});
Information about triggers: https://firebase.google.com/docs/functions/auth-events