2

I'm new to programming and only as a hobby, usually if I have a problem I can find the answer on the internet somewhere, but having spent best part of 2 days and still can't figure this one out. I'm programming an android app using kotlin and android studio. First question asked, please be gentle!

I have a date saved in Firestore as timestamp saved with this code through hashmap

    val dateFormat = SimpleDateFormat("dd-MM-yyyy")
    val date = findViewById<TextView>(R.id.textMatchDate).text.toString()
    val timeStamp = Timestamp(dateFormat.parse(date)

timeStamp is then saved to firestore.

My code for retrieval is

        val date = "01-01-2020"
        val date1 = dateFormat.parse(date)
        val startDate = Timestamp(date1)

val db = FirebaseFirestore.getInstance()
        db.collection("snookerResults")
            .whereGreaterThan("date", startDate)
            .whereEqualTo("homeTeam", team)
            .get()
            .addOnSuccessListener {...}

I've put the means 0f getting startDate for simplicity it is is derived programatically but is string of the same format. I get an empty array despite knowing ther are results that should be returned. If I comment out the whereGreaterThan line I get all results returned.

I have Log outputs to illustrate the problem when I run normally I get this output:-

2020-08-29 23:27:04.858 17112-17112/com.example.aggregatecalculator I/handicap: chosen team is The Brunswick

2020-08-29 23:27:05.086 17112-17112/com.example.aggregatecalculator I/handicap: startdate is Timestamp(seconds=1577836800, nanoseconds=0)

If I comment out the whereGreaterThan line then I get this output

2020-08-29 23:37:08.331 18164-18164/com.example.aggregatecalculator I/handicap: chosen team is The Brunswick

2020-08-29 23:37:08.582 18164-18164/com.example.aggregatecalculator I/handicap: startdate is Timestamp(seconds=1577836800, nanoseconds=0)

2020-08-29 23:37:08.583 18164-18164/com.example.aggregatecalculator I/handicap: date is [Wed Jan 01 00:00:00 GMT+00:00 2020, Wed Sep 30 00:00:00 GMT+01:00 2020]

2020-08-29 23:37:08.793 18164-18164/com.example.aggregatecalculator I/handicapresults: date is Timestamp(seconds=1583712000, nanoseconds=0)

2020-08-29 23:37:08.793 18164-18164/com.example.aggregatecalculator I/handicapresults: date is Timestamp(seconds=1575244800, nanoseconds=0)

2020-08-29 23:37:08.793 18164-18164/com.example.aggregatecalculator I/handicapresults: date is Timestamp(seconds=1569798000, nanoseconds=0)

2020-08-29 23:37:08.794 18164-18164/com.example.aggregatecalculator I/handicapresults: date is Timestamp(seconds=1572825600, nanoseconds=0)

2020-08-29 23:37:08.794 18164-18164/com.example.aggregatecalculator I/handicapresults: date is Timestamp(seconds=1582502400, nanoseconds=0)

2020-08-29 23:37:08.794 18164-18164/com.example.aggregatecalculator I/handicapresults: date is Timestamp(seconds=1584921600, nanoseconds=0)

2020-08-29 23:37:08.795 18164-18164/com.example.aggregatecalculator I/handicapresults: date is Timestamp(seconds=1568588400, nanoseconds=0)

2020-08-29 23:37:08.795 18164-18164/com.example.aggregatecalculator I/handicapresults: date is Timestamp(seconds=1574035200, nanoseconds=0)

2020-08-29 23:37:08.795 18164-18164/com.example.aggregatecalculator I/handicapresults: date is Timestamp(seconds=1571612400, nanoseconds=0)

2020-08-29 23:37:08.796 18164-18164/com.example.aggregatecalculator I/handicapresults: date is Timestamp(seconds=1571007600, nanoseconds=0)

As you can see timestamp is same format and 3 returned timestamp's are greater than the startdate so in theary should return with the whereGreaterThan clause

enter image description here

fun getNewHcap(team: String){
val players = arrayListOf<String>()
val db = FirebaseFirestore.getInstance()
db.collection("SnookerPlayers")
    .whereEqualTo("league", "Big Table Monday")
    .whereEqualTo("team", team)
    .get()
    .addOnSuccessListener { task ->
        for (doclist in task){
            val player = doclist["player"].toString()
            players.add(player)
        }
        val dates = hcapMinMaxDate()
        val dateFormat = SimpleDateFormat("dd-MM-yyyy")
        val date = "01-01-2020"
        val date1 = dateFormat.parse(date)
        val startDate = Timestamp(date1)
        val endDate = Timestamp(dates[1])
        Log.i("handicap", "startdate is $startDate")
       // Log.i("handicap", "startdate is $endDate")

        val db = FirebaseFirestore.getInstance()
        db.collection("snookerResults")
            //.whereGreaterThan("date", startDate)
            .whereEqualTo("homeTeam", team)

           //.whereLessThan("date", endDate)
            .get()
            .addOnSuccessListener { task ->
                for (docList in task){
                   // val player = docList["home player 1"].toString()
                    val date = docList["date"].toString()

                    Log.i("handicapresults", "date is $date")
                }
            }


        Log.i("handicap", "date is $dates")

    }
Log.i("handicap", "chosen team is $team")
  • 2
    Please edit your question to include: 1) a screenshot of a document you'd expect to be returned by this query, 2) the code that actually handles the results of the query, so that shows the unexpected result. It's typically easiest for us to see what's going on if you log the unexpected results. – Frank van Puffelen Aug 29 '20 at 19:52
  • Please add what Frank van Puffelen asked for and please also respond with @. – Alex Mamo Aug 30 '20 at 05:49
  • @Frank not sure what screenshot you require, have included firestore field, also put fuller code snippet on and the log outputs as thats as far as I've got with doing something with the results. I use log results to check on whats coming back before carrying on. – Dave Hannigan Aug 30 '20 at 07:49
  • Thanks for the updates. I don't immediately see what's going wrong. Maybe @AlexMamo has an idea with the new data. – Frank van Puffelen Aug 30 '20 at 14:41
  • @DaveHannigan Please add the structure of the entire document not only the value of the `date` property. – Alex Mamo Aug 31 '20 at 07:29
  • @AlexMamo I have changed the screen grab to basic document structure – Dave Hannigan Aug 31 '20 at 08:02
  • 1
    @FrankvanPuffelen Hey, puf. Yep, I've found the solution for OP's issue and I added it as an answer. It seems to work now. Thanks – Alex Mamo Aug 31 '20 at 10:34

1 Answers1

2

I get an empty array despite knowing there are results that should be returned. If I comment out the whereGreaterThan() line I get all results returned.

You are getting an empty array most likely because of the following line of code:

db.collection("snookerResults")
    .whereGreaterThan("date", startDate)
    .whereEqualTo("homeTeam", team)
    .get()
    .addOnSuccessListener {...}

And this is because calling .whereGreaterThan() along with .whereEqualTo() in the same query, require an index. This index can be created manually in your Firebase Console or if you are using Android Studio, you'll find in the logcat a message that sounds like this:

FAILED_PRECONDITION: The query requires an index. You can create it here: ...

You can simply click on the link or copy and paste the URL into a web browser and your index will be created automatically. Wait a few minutes until the index is created and you'll get the desired results.

However, this approach might not be the best one, since you need to create an index for each homeTeam in your database. It will work if you have a few or a fixed number of teams but it will be hard if you have lots of them, case in which it's recommended to duplicate the data. This practice is called denormalization and it's quite common practice when it comes to Cloud Firestore. If you are new to the NoSQL database, for a better understanding, I recommend you see this video, Denormalization is normal with the Firebase Database. It's for Firebase Realtime Database but the same principles apply to Cloud Firestore. Besides that, I think you might also be interested in my answer from the following post:

What is denormalization in Firebase Cloud Firestore?

So in your particular case, I'd create a new collection that looks like this:

Firestore-root
  |
  --- homeSnookerResults (collection)
         |
         --- homeTeamId (document)
               |
               --- allResults (collection)
                     |
                     --- resultIdOne (document)
                           |
                           --- //result object properties

In this case, a query that looks like this, will do the trick:

db.collection("homeSnookerResults")
    .document(homeTeamId)
    .collection("allResults")
    .whereGreaterThan("date", startDate)
    .get()
    .addOnSuccessListener {...}

Case in which, no index is required.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • many thanks for that, had not realised and nothing about indexes seemed to come up in my searches. Works perfectly. If only I'd read full logcat instead of just focusing on results it would have answered my query. I'll check that first in future – Dave Hannigan Aug 31 '20 at 10:29
  • 1
    Given the hassle I had finding an answer to my query I think it should, thanks again – Dave Hannigan Aug 31 '20 at 14:31