-1

I have a database like this

users/UID1/"Username" (of user 1)

 /UID2/"Username" (of user 2)
 /UID3/"Username" (of user 3)
 /UID4/"Username" (of user 4)

and so on..

I would like to check if the username exist but I don't manage to go in a loop with all existing UID. For now I have tried :

let databaseRef = Database.database().reference()        
            databaseRef.child("users").child("uid").child("Username").observeSingleEvent(of: DataEventType.value, with: { (snapshot) in
                switch snapshot.value {
                case let value as Bool where value:
                    // value was a Bool and equal to true
                    print ("username found")
                default:
                    // value was either null, false or could not be cast
                    print ("username not found")
                }
            })

        }

I don't know what to put instead of child("uid") to loop into every uid in my database and check if a username exists

Thanks for your help !

Bonilla
  • 99
  • 2
  • 11
  • Hello, there is no way to loop in every UID? – Bonilla Jun 18 '18 at 09:32
  • Please forget my previous comment, my coffee hasn't kicked in yet. It is possible but it would be easier to change the datastructure. You can check out [Daniel's answer](https://stackoverflow.com/a/50906771/4916627) – André Kool Jun 18 '18 at 09:56
  • Check the question I linked. Specifically check my own answer, as the accepted answer loads more data than necessary: https://stackoverflow.com/a/50494190 – Frank van Puffelen Jun 18 '18 at 14:57

2 Answers2

1

In Android

A DataSnapshot instance contains data from a Firebase Database location. Any time you read Database data, you receive the data as a DataSnapshot.

DataSnapshot have exist() method that checking the record is exist or not. Base on this document https://firebase.google.com/docs/reference/android/com/google/firebase/database/DataSnapshot.html#exists()

Like :

reciverDatabase.getRef().addListenerForSingleValueEvent(new ValueEventListener() {
                        @Override
                        public void onDataChange(DataSnapshot dataSnapshot) {
                            if (dataSnapshot.exists()) {
                                reciverDatabase.child(Constants.CONVERSATION_UNREAD_COUNT).setValue(dataSnapshot.getValue(Long.class) + 1);
                            }
                        }

                        @Override
                        public void onCancelled(DatabaseError databaseError) {
                            Crashlytics.logException(databaseError.toException());
                            sendMessageListener.onSendMessageFailure(databaseError.getMessage());
                        }
                    });

In iOS :

you can check it like :

For objective C : exists

Desc : Return YES if the DataSnapshot contains a non-null value.

You can read more from this document https://firebase.google.com/docs/reference/ios/firebasedatabase/api/reference/Classes/FIRDataSnapshot#/c:objc(cs)FIRDataSnapshot(im)exists

For Swift :

exists()

func exists() -> Bool

https://firebase.google.com/docs/reference/swift/firebasedatabase/api/reference/Classes/DataSnapshot#/c:objc(cs)FIRDataSnapshot(im)exists

Community
  • 1
  • 1
Mayur Patel
  • 2,300
  • 11
  • 30
1

The easiest way of achieving this is when registering a user, create the user with their unique UID and save all their data inside there like you're doing BUT also create a node called "usernames" that simply holds all the usernames that are signed up with the key as their username and the value as 1 like so:

Usernames {
 - username: 1
}

When a user signs up and then goes to enter a username, you can check if it exists like so:

let username = "username that user has typed in"

let reference = Database.database().reference()
reference.child("usernames").observeSingleEvent(of: .value, with: { (snapshot) in

    if snapshot.hasChild(username) {

        print("Already exists")

    } else {

        print("Doesn't exist")

    }

}, withCancel: nil)

EDIT:

Thanks to @FrankvanPuffelen, here's a much more efficient way of doing this - without looping through every single username.

let reference = Database.database().reference()
reference.child("usernames").child(username).observeSingleEvent(of: .value, with: { (snapshot) in

    if snapshot.exists() {

        print("Username already exists")

    } else {

        print("Username doesn't already exist")

    }

}, withCancel: nil)
Daniel Dramond
  • 1,538
  • 2
  • 15
  • 26
  • 1
    Instead of using 1 as a value you can also use the uid to link a username to a user. – André Kool Jun 18 '18 at 09:57
  • @AndréKool Great point. Very useful – Daniel Dramond Jun 18 '18 at 09:57
  • Thanks both! it's a good point – Bonilla Jun 18 '18 at 10:23
  • Instead of using hasChild() property you can use exist() for it. You may check more in this document https://firebase.google.com/docs/reference/swift/firebasedatabase/api/reference/Classes/DataSnapshot#/c:objc(cs)FIRDataSnapshot(im)exists – Mayur Patel Jun 18 '18 at 10:27
  • @MayurPatel This would check if the usernames node exists more than if the username itself exists inside of the usernames node. As confusing as that sounds... – Daniel Dramond Jun 18 '18 at 10:28
  • @DanielDramond yes Both will work here. But i think based on the question you exist() function is checking weather record exist or not. But hasChild is check value as well as key is exist or not. – Mayur Patel Jun 18 '18 at 10:42
  • I have also this error message : *** Terminating app due to uncaught exception 'InvalidPathValidation', reason: '(hasChild:) Must be a non-empty string and not contain '.' '#' '$' '[' or ']'' - my usernames can have username like Bonilla-001 or Bonilla$$$ – Bonilla Jun 18 '18 at 13:21
  • @Bonilla Unfortunately keys cannot contain characters like that. There are workarounds such as using Bonilla(dollar) as your key and when you fetch it, you can change the (dollar) to an actual $ in Swift – Daniel Dramond Jun 18 '18 at 13:24
  • 1
    Please please please don't load all user names if you need to check if one exists. It's a waste of bandwidth. Instead `reference.child("usernames").child(username).observeSingleEvent(of: .value, with: { (snapshot) in if snapshot.exists() {` as I've shown here: https://stackoverflow.com/a/50494190/209103 – Frank van Puffelen Jun 18 '18 at 14:56
  • @FrankvanPuffelen Spot on. A much for efficient approach. Will edit answer – Daniel Dramond Jun 18 '18 at 14:57
  • 1
    Thanks Daniel. And thanks for helping a fellow developer learn about the lookup maps. These are always confusing for devs new to Firebase/NoSQL, since such things are built into most relational databases. – Frank van Puffelen Jun 18 '18 at 15:02
  • @FrankvanPuffelen As a huge fan of Firebase, I'm more than happy to help. I've updated my answer to include your approach. – Daniel Dramond Jun 18 '18 at 15:07
  • Just one more question @AndréKool : when you said :Instead of using 1 as a value you can also use the uid to link a username to a user --> how can you set this uid value to the username.text ? : ref.child("usernames").setValue([username: (Auth.auth().currentUser?.uid)!]) -->doesn't work. – Bonilla Jun 18 '18 at 16:39