简体   繁体   中英

Cloud Firestore: Query to check if a username exists

I have a problem regarding my userNameExistsAlready -method in my Android App.
Basically, I have a Cloud Firestore database with the collection user .
Its documents are only populated with username , password and email (all String). Document IDs are auto-generated. I've created an RegisterActivity which works fine. Here is the onCreate(..) method of my RegisterActivity:

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);

userNameInput = (TextInputEditText) findViewById(R.id.userNameInput);
emailInput = (TextInputEditText) findViewById(R.id.emailInput);
passwordInput = (TextInputEditText) findViewById(R.id.passwordInput);
Button registerButton = findViewById(R.id.createAccountButton);

registerButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        userNameText = userNameInput.getText().toString();
        emailText = emailInput.getText().toString();
        passwordText = passwordInput.getText().toString();
        if (validateInputs()) {
            saveUser();
        } else {
            Toast.makeText(RegisterActivity.this, "Inputs invalid! Please correct.", Toast.LENGTH_SHORT).show();
        }
    }

    private void saveUser() {
        if (new UserDatabaseModel(userNameText, passwordText, emailText).saveUser()) {
            Toast.makeText(RegisterActivity.this, "User Created!", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(RegisterActivity.this, "User Creation Failed!", Toast.LENGTH_SHORT).show();
        }
    }

Here is my UserDatabaseModel.java file:

public class UserDatabaseModel {
    public final static String DATABASE_DECLARATION = "user";
    private final FirebaseFirestore db = FirebaseFirestore.getInstance();
    private String username;
    private String password;
    private String email;

    public UserDatabaseModel(String username, String password, String email) {
        this.username = username;
        this.password = password;
        this.email = email;
    }
    public UserDatabaseModel() {

    }

    public boolean saveUser() {

        try {
            db.collection(UserDatabaseModel.DATABASE_DECLARATION).document().set(this);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public String getUsername() {
        return username;
    }
    public String getPassword() {
        return password;
    }
    public String getEmail() {
        return email;
    }
}

My validateInputs() -method does some basic stuff such as checking the length of the inputs, as well as it calls if (userNameExistsAlready()) { return false} .
Now the important part, the userNameExistsAlready() -method:

    private boolean userNameExistsAlready() {
        Query mQuery = db.collection(UserDatabaseModel.DATABASE_DECLARATION)
                .whereEqualTo("username", userNameText);

        mQuery.addSnapshotListener(new EventListener<QuerySnapshot>(){
            @Override
            public void onEvent(QuerySnapshot queryDocumentSnapshots, FirebaseFirestoreException e) {
                for (DocumentSnapshot ds: queryDocumentSnapshots){
                    if (ds!=null && ds.exists()){
                        Toast.makeText(RegisterActivity.this, "Username Exists Already!", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });
        return false;
}

This code always finds at least one DocumentSnapshot with the given username, the one I just typed in(of course without having it actually saved, because the save-method only gets called if validateInputs() == true [this is the thing that confuses me]), and more if there are more saved already. Do I miss something here (I thought at least the ds.exists() -call would make sure these files are IN the DB already) or what could be the problem?

Thanks

I use it like this

public void checkFieldIsExist(String key, String value, OnSuccessListener<Boolean> onSuccessListener) {
    db.collection("users").whereEqualTo(key, value).addSnapshotListener(new EventListener<QuerySnapshot>() {
        private boolean isRunOneTime = false;

        @Override
        public void onEvent(QuerySnapshot queryDocumentSnapshots, FirebaseFirestoreException e) {
            if (!isRunOneTime) {
                isRunOneTime = true;
                List<DocumentSnapshot> snapshotList = queryDocumentSnapshots.getDocuments();
                if (e != null) {
                    e.printStackTrace();
                    String message = e.getMessage();
                    onSuccessListener.onSuccess(false);
                    return;
                }

                if (snapshotList.size() > 0) {
                    //Field is Exist
                    onSuccessListener.onSuccess(false);
                } else {
                    onSuccessListener.onSuccess(true);
                }

            }
        }
    });
}

Usage

 checkFieldIsExist("username", "dummy", new OnSuccessListener<Boolean>() {
                            @Override
                            public void onSuccess(Boolean aBoolean) {
                                if(aBoolean){
                                    //
                                }else{
                                    //username is exist
                                }
                            }
                        });

You can use it instead of OnSuccesListener

public interface OnCompleteListener<T> {
    void onComplete(T result);
}

First of all, there is no need to use addSnapshotListener . This is used only when you want to get realtime updates from the database but it's not your case. You only want to check a username for existens and for that, only a get() call is required.

mQuery.get().addOnCompleteListener(/* ... */)

Second, according to this post , ds!=null && ds.exists() is not required. You only need to check if ds.exists() .

And the last thing you need to know is that you can not rely on what value your userNameExistsAlready() method returns. In most cases it will be false and this is because the onEvent() method in your case or onComplete() / onSuccess() in case of using a get() call, are asynchronous . This means that by the time your method returns the result, you haven't finished loading the data from the database. So a quick solve for this would be to use all your logic inside the onEvent() method or if you want to use it outside, I recommend you see the last part of my anwser from this post and also take a look at this video .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM