skip to Main Content

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',
      );
    }
  }

2

Answers


  1. 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.

    Login or Signup to reply.
  2. 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search