0

Trying to use Dan McGrath's suggested Document Agnostic solution to querying Firestore for random documents, along with the Rinse in Repeat suggestion for pulling multiple random documents.

This code occasionally comes up with nil documents (doesn't always return a document). I think my query is off and am looking for guidance/ideas on how to correct he problem - Thanks

func getRandomPlateOne() {
        let plateOneRef = db.collection("plates")
        plateOneRef.whereField("random", isGreaterThan: randomNumberOne).order(by: "random").limit(to: 1).getDocuments { (snapshot, error) in
            if snapshot!.isEmpty {
                plateOneRef.whereField("random", isLessThanOrEqualTo: self.randomNumberOne).order(by: "random", descending: true).limit(to: 1)
            } else {
                guard let documents = snapshot?.documents else {return}
                for document in documents {
                    let data = document.data()
                    let newPlate = Plate.init(data: data)
                    self.randomPlateOne = [newPlate]
                    print(self.randomPlateOne)
                }
            }
        }
    }

EDIT -Though I had this figured out, that passing the random number into a variable, and then using that variable in my query would make certain that the same random number was being used whether the query was going greaterThan or lessThanAndEqualTo. Still getting an occasional nil back from Firestore. My query must still be off.

New code:

func getRandomPlateOne() {
        let collectionRef = db.collection("plates")
        collectionRef.whereField("random", isGreaterThan: randomNumberOne).order(by: "random").limit(to: 1).getDocuments { (snapshot, error) in
            if snapshot!.isEmpty {
                collectionRef.whereField("random", isLessThanOrEqualTo: self.randomNumberOne).order(by: "random", descending: true).limit(to: 1)
            } else {
                guard let documents = snapshot?.documents else {return}
                for document in documents {
                    let data = document.data()
                    let newPlate = Plate.init(data: data)
                    self.randomPlateOne = [newPlate]
                    print(self.randomPlateOne)
                    }
                }
            }
        }

func generateARandomNumber() {
        randomNumberOne = UInt64.random(in: 0 ... 9223372036854775807)
        }

var randomNumberOne: UInt64 = 0

EDIT - Function has evolved. I am still unable to get the step between checking if first condition returned a document or not, and moving to a sometimes necessary second query. This works, but I am using a fixed UInt64.

var randomNumberOne: UInt64 = 8190941879098207969 (higher than any other in my collection)

func getRandomPlateOne() {
        let randomPlateRef = db.collection("plates")

            randomPlateRef.whereField("random", isGreaterThan: randomNumberOne).order(by: "random").limit(to: 1).getDocuments { (snap, error) in
                if snap!.isEmpty {
                randomPlateRef.whereField("random", isLessThanOrEqualTo: self.randomNumberOne).order(by: "random", descending: true).limit(to: 1).getDocuments { (snap, error) in
                    print("This is the snapshot from the second query. \(snap!) ")
                    guard let documents = snap?.documents else {return}
                    for document in documents {
                        let data = document.data()
                        let newPlate = Plate.init(data: data)
                        self.plates.append(newPlate)
                        print(self.plates)
                    }
                }
            }
        }
  • It hit me late last night, I think I am using two different random numbers, in this function. So if there is not a document available above the randomNumber, I am generating a new randomNumber and then looking for a document below it. I need to create a variable for the first randomNumber, that is then utilized in the second part of the generator, if going lower in the range is required. – Eric M. Seitz May 15 '19 at 15:54
  • This only gets one random document. I will wash, rinse, repeat, to get three more, into the plates array. – Eric M. Seitz May 16 '19 at 21:26

1 Answers1

0

As I said in my above comment, I was using two different random numbers for working up the range of documents, or down the range of documents when necessary.

I created a generateARandomNumber function, that is called in my viewDidLoad function.

func generateARandomNumber() {
        randomNumber = UInt64.random(in: 0 ... 9223372036854775807)
    }

That number is then passed into a variable, that is used within my getARandomPlate(a Firestore document).

I am now using the same random number, whether searching for a document whose random number isGreaterThan the viewDidLoad generated random number or if I end up querying for a isLessThanOrEqualTo document.

EDIT -

Working code:

let db = Firestore.firestore()
    var randomNumberOne: UInt64 = 0
    var plates = [Plate]()

func getRandomPlateOne() {
        let randomPlateRef = db.collection("plates")

            randomPlateRef.whereField("random", isGreaterThan: randomNumberOne).order(by: "random").limit(to: 1).getDocuments { (snap, error) in
                guard let documents = snap?.documents else {return}
                for document in documents {
                    let data = document.data()
                    let newPlate = Plate.init(data: data)
                    self.plates.append(newPlate)
                    print(self.plates)
                }

                if snap!.isEmpty {
                randomPlateRef.whereField("random", isLessThanOrEqualTo: self.randomNumberOne).order(by: "random", descending: true).limit(to: 1).getDocuments { (snap, error) in
                    guard let documents = snap?.documents else {return}
                    for document in documents {
                        let data = document.data()
                        let newPlate = Plate.init(data: data)
                        self.plates.append(newPlate)
                        print(self.plates)
                    }
                }
            }
        }
    }

func generateARandomNumber() {
        randomNumberOne = UInt64.random(in: 0 ... 9223372036854775807)
    }