0

I am trying to use Firebase 3 and Swift 3, to make an app that allows users to create "tests", and the purpose is you're going to be shown a completely random test from the database.

My table:

Users:
- uid
    - email

tests
   - id
      - title
      - user_uid

How do I random select any child from "tests", so I can display them to the user? Should I change my structure somehow?

By this I mean lets say I have this:

tests:
- 12391239123
    - title: "My first test"
    - user_uid: 12312345
- 59696995883
    - title: "Second test"
    - user_uid 12352355

I want to select one of these two objects, so I can display them to the user. And it has to be completely random.

Also is it possible to query the database, so I get all childs where user_uid is equal to the user uid I supply? If so, how?

Paul Beusterien
  • 27,542
  • 6
  • 83
  • 139
Mads Odgaard
  • 33
  • 2
  • 7

2 Answers2

2

Try changing your JSON tree to this :-

Users:
  - uid
     - email

tests
  - noOfTotalTest : 4 // Lets say 4
  - id
     - title
     - user_uid
     - index   // Just index of the post

Now use this codeBlock :-

    FIRDatabase.database().reference().child("tests/noOfTotalTest").observeSingleEvent(of: .value, with: {(Snap) in


        let totalNoOfTest = Snap.value as! Int
        print(totalNoOfTest)
        let randNum = Int(arc4random_uniform(UInt32(totalNoOfTest))) + 1
        print(randNum)
        FIRDatabase.database().reference().child("tests").queryOrdered(byChild: "index").queryEqual(toValue: randNum).observeSingleEvent(of: .value, with: {(Snapshot) in

            print(Snapshot.value!)

        })
    })

NoW whenever you post a test to your database you gotta do these things:-

  • Query for the total no of tests in the DB, noOfTotalTest
  • Once retrieved increment it by +1 and update noOfTotalTest and put it in with other of the test details and set it to your DB
  • And the process carries on....

PS:- For making the post just/ SAVING:-

  FIRDatabase.database().reference().child("tests/noOfTotalTest").observeSingleEvent(of: .value, with: {(Snap) in 

if Snap.exists(){

            // This is not the first post

            let totalNoOfTest = Snap.value as! Int

            FIRDatabase.database().reference().child("tests").childByAutoId().setValue(["userID" : UID, "details" : Details, "index" : totalNoOfTest + 1])
   FIRDatabase.database().reference().child("tests/noOfTotalTest").setValue(totalNoOfTest + 1)
        } else {

         // This is your first post

         FIRDatabase.database().reference().child("tests").childByAutoId().setValue(["userID" : UID, "details" : Details, "index" : 1])
   FIRDatabase.database().reference().child("tests/noOfTotalTest").setValue(1)  

        }

})

To extend this for you to be able to delete, you can save the indexes that are active in your node's which you need to randomise.

For that add this to your JSON tree:-

active_Indexes :{

   12 : true,
   09 : true,
   198 : true,
   11: true,
   103 : true,
  }

Now what you need is to store these INDEX in an dictionary , then randomise the array element :-

 var localIndexDirectory = [Int : Bool]

 //Listen to any changes to the database, and update your local index directory accordingly 


override func viewDidLoad() {
    super.viewDidLoad()


    FIRDatabase.database().reference().child("active_Index").observe(.childRemoved, with: {(Snap) in

        print(Snap.value)
        let keyToBeChanged = Int(Snap.key)!
        self.localIndexDirectory.removeValue(forKey: keyToBeChanged)
        print(self.localIndexDirectory)

    })

    FIRDatabase.database().reference().child("active_Index").observe(.childAdded, with: {(Snap) in

        print(Snap)
        let keyToBeChanged = Int(Snap.key)!
        self.localIndexDirectory.updateValue(true, forKey: keyToBeChanged)
        print(self.localIndexDirectory)

    })
}

This will keep your directory updated for the indexes available(SINCE .observe is a continuos thread in your network thread) in your database, then all you need is to randomise those indexes at that particular time and query that test for that particular index. But now to activate the Deleting function in your app you also need to modify your saving function i.e whenever you save a new node to your database, make sure you also append the active_Indexes node in your DB, with that particular index.

PPS:- You would also need to update your security rules for dealing with different authentication states.

Dravidian
  • 9,945
  • 3
  • 34
  • 74
0
  • First of all, you have to query all the data from firebase. Then you can use normal random function to get a random value from the snapshot.(2nd part)
  • To query based on user id you can use the following code (1st part)

    ref.child("users").queryEqualToValue("userId").observeEventType(.Value, withBlock: { snapshot in
    print(snapshot)
    }
    
    
    
    
    for _ in 1...10 {
     //generate a random number between 1 and the amount of questions you have
     var randomNumber = Int(arc4random_uniform(amountOfQuestions - 1)) + 1
    
    //The reference to your questions in firebase (this is an example from firebase itself)
    let ref = Firebase(url: "https://dinosaur-facts.firebaseio.com/dinosaurs")
    //Order the questions on their value and get the one that has the   random value
            ref.queryOrderedByChild("value").queryEqualToValue(randomNumber).observeEventType(.ChildAdded, withBlock: { snapshot in
    //Do something with the question
    println(snapshot.key)
     })
    }
    
rajtharan-g
  • 432
  • 5
  • 14
  • so lets say I have 100,000 users in my database, I should retrieve 100,000 values? are you sure this is an optimal solution? – Mads Odgaard Nov 23 '16 at 13:56
  • This might not be the optimal solution, but there is no specific function provided by firebase for this purpose. – rajtharan-g Nov 23 '16 at 14:04