I have a Firebase realtime database that acts as the backend to my Android app. The app is to display fixtures for a soccer league. The results are shown in a listview in a fragment.
I have a record structure like so;
awayTeam
date
gameID
hometeam
pitch
time
What I'd like to do is group games by a specific date in chronological order. So if I had 10 games (records), the first 5 played on the 01/04/2018 and the next 5 played on the 01/05/2018, I want to be able to present all of the 01/04/2018 games in there own grouped box and so forth.
In SQL Group By would be easily achieved, but I'm unsure if this is achievable either through a query or if I have to write a recursive function that will build the tree view up and order them by data at the array level.
Any help is appreciated.
There is no group by operation in Firebase. In fact, you'll find that many operations you're used to from relational databases are missing from Firebase.
What you get in return is a more flexible data model. For example: if you want to group your games by a specific data, you could store them under that specific date as a key:
games
2018-02-28
game1: { ... }
game2: { ... }
game3: { ... }
2018-03-01
game4: { ... }
Now you can do a simple lookup for all games for a given date.
If you want to group the games by different criteria, you'll probably keep the original list and then create lookup lists (also often called indexes) for each criterium. E.g.
gamesByDate
2018-02-28
game1: true
game2: true
game3: true
2018-03-01
game4: true
gamesByTeam
Team1
game1: true
game2: true
Team2
game1: true
game3: true
game4: true
Now you can look up the game IDs either by date or by team, and then look up the properties for each game by that ID.
Related
I'm making an android app where user can find a book in his/her vicinity and buy it if interested. I am using firebase and geoqueries/geofire.
I want to make a SearchActivity where user can search a book by it's title in his/her vicinity.
my Firebase Database Structure looks like :
books
PushKey
g:
l:
0:
1:
name:"some book name"
If i try to query this with some book name, it works fine using :
myRef.orderByChild("name").equalTo("some book name").addChildEventListener()....//The rest of the code here...
If i try to query nearby books,then also it works fine using :
geoQuery = geoFire.queryAtLocation(myLocation, 10);
I'm stuck at combining these two.
How can i search for a specific book name only in the vicinity?
For example : I want to search a book whose name is "ABCD" and is in a radius of 10km.
OR
Search a book by name and tell which one is nearest(In case several books are uploaded with same name at different locations).
Is it possible to do so? If not, what workaround(maybe other than firebase, but has to cheap and affordable) can i opt for where i can achieve this desired result?
The Firebase Database can only query by a single property. The fact that GeoFire does something that is seemingly at odds with that (querying by longitude and latitude) is because it combines these values into a single property in a magical format called a geohash (the g property in your JSON).
Combining values into a single property is the only way to get Firebase to filter on multiple values. For example, you could prefix the g property with your book title to get some book name_geohashvalue and could then filter on that.
The two main problems with that:
This only works if you know the entire book title, you can do a prefix match on the title, as you'll already need to use the prefix match for the geohash.
This is not built in to GeoFire, so you will have to fork that library and build it yourself.
If you do try to do this yourself, and get stuck, we can try to help. But fair warning: this won't be trivial, and you'll need to understand how geohashes, geofire, and Firebase's query model work quite well. For an intro, I recommend watching the video of my talk on performing geoqueries on Firebase and Firestore.
If you want something a bit less involved, you have two main options:
Retrieve all nodes within range, and then filter for the book title client-side.
Store a separate GeoFire tree for each book title, so that you can initialize your GeoFire object based on the book title, and only get keys within range for that specific book title.
Between these two, I'd recommend starting with #1.
I'm using a Firebase Firestore for android to store data. I tried to search data from documents.
My Firestore structure is:
Collection (Products) - Document (Auto Generated ID) - Field (NumberOfPeople,OfferStartDate,OfferEndDate,OfferPrice,Location)
I wrote query for search data on those fields.
CollectionReference collectionOfProducts = db.collection("Products");
collectionOfProducts
.whereEqualTo("Location", location)
.whereGreaterThanOrEqualTo("OfferPrice", offerPrice)
.whereLessThanOrEqualTo("OfferPrice", offerPrice)
.whereGreaterThanOrEqualTo("OfferStartDate", date)
.whereLessThanOrEqualTo("OfferEndDate", date)
.get()
I want search result like this: An offer which is between start date and end date, where offer price is greater than equal or less than equal on give price range. This query is not working in android studio.
How to do this in firestore firebase?
According to the official documentation regarding Cloud Firestore queries, please note that there some query limitations:
In a compound query, range (<, <=, >, >=) and not equals (!=, not-in) comparisons must all filter on the same field.
So a Query object that contains a call to both methods:
.whereGreaterThanOrEqualTo("OfferStartDate", date)
.whereLessThanOrEqualTo("OfferEndDate", date)
Is actually not possible, as "OfferStartDate" and "OfferEndDate" are different properties.
The best solution I can think of is to use only one of these method calls and do the other filtering on the client.
Another possible solution might be to use denormalization and duplicate the data
in certain intervals. In this way, you'll always know the time periods and you'll be able to create the corresponding queries.
To the best of my knowledge, Firestore only lets you use where<Greater/Less>ThanOrEqualTo() and where<Greater/Less>Than() a single field and all other filter operations on other fields can only be whereEqualTo().
Some workarounds for your specific case include -
1) Modifying your query to
collectionOfProducts
.whereGreaterThanOrEqualTo("OfferStartDate", date)
.whereEqualTo("Location", location)
.get()
And then performing the subsequent filtering on the result in your app code.
Alternately, you can perform your filter on "OfferPrice" and "Location" in your query and the remaining filters can be applied to the query result.
2) You can use firebase functions or other server code to write logic that performs customized filtering and fetch the result that way.
i was having same issue with this, but i found a work around that takes sometime to write.
lets say you want to search for a particular keyword(in this case the value of a field inside a document), and you want firebase to search multiple field instead of just looking for 1 particular field.
this is what you want to do.
const searchTerm = document.createElement('input')
db.collection('collection').where('field1', '==', `${searchTerm.value}`)
.get()
.then((snapshot) => {
if(snapshot.size === '0'){
db.collection('collection').where('field2', '==', `${searchTerm.value}`)
.get()
.then((snapshot) => {
if(snapshot.size === 0) {
db.collection......and repeat
}
})
}
})
in summary, the above code is basically telling js to search for the term again with a different field if the result of the previous query is 0. I know this solution might not be able to work if we have a large quantity of fields. But for folks out there that are working with small number fields, this solution might be able to help.
I really do hope firestore one day would allow such feature, but here is the code it worked fine for me.
the problem I have now is to allow search input to be able to search without have me to complete the word. I do currently have an idea how this would be, but just need some time to put together.
I have a quick question about the best practices for data structure in a firebase database.
I want users of my app to be able to maintain a friends list. The firebase documentation recommends creating a schema (not sure if thats the proper word in this context) that is as flat as possible. Because of this I thought it would be a good idea to separate the friends section from the player section in the database like so:
{
"players":{
"player1id":{
"username":"john",...
},
"player2id": ...,
"player3id": ...
}
"friends": {
"player1id"{
"friends":{
"friend1Id":true,
"friend2Id":true
}
},
}
"player2id"{
"friends":{
"friend1Id":true,
"friend2Id":true
}
},
}
}
So my questions are as follows:
Is this a good design for my schema?
When pulling a friends list for one player, will the friends lists of EVERY player be pulled? and if so, can this be avoided?
Also, what would be the best way to then pull in additional information about the friends once the app has all of their IDs. e.g. getting all of their user names which will be stored as a string in their player profile.
Is this a good design for my schema?
You're already thinking in the right direction. However the "friends" node can be simplified to:
"friends": {
"player1id": {
"friend1Id":true,
"friend2Id":true
}
}
Remember that Firebase node names cannot use the character dot (.). So if your IDs are integer such as 1, 2, and 3 everything is OK, but if the IDs are username be careful (for example "super123" is OK but "super.duper" is not)
When pulling a friends list for one player, will the friends lists of EVERY player be pulled? and if so, can this be avoided?
No. If you pull /friends/1 it obviously won't pull /friends/2 etc.
Also, what would be the best way to then pull in additional information about the friends once the app has all of their IDs. e.g. getting all of their user names which will be stored as a string in their player profile.
Loop through the IDs and fetch the respective nodes from Firebase again. For example if user 1 has friends 2, 3, and 4, then using a for loop fetch /players/2, /players/3, and /players/4
Since firebase pull works asynchronously, you might need to use a counter or some other mechanism so that when the last data is pulled you can continue running the completion code.
This question already has answers here:
Query based on multiple where clauses in Firebase
(8 answers)
Closed 7 years ago.
I'm using firebase on my android app. I need help to find an issue to my trouble. I want to do a request like this: I was using the oderbyChild("date") to oder my data from the nearest date to the farest by doing this.
MyApplication.backend.child(urls).orderByChild("value").addValueEventListener(new ValueEventListener() {
}
now i want to this select all where the activity value is done and order theme by my date value. i have write this :
MyApplication.backend.child(urls).orderByChild("task").equalTo("done").addValueEventListener(new ValueEventListener(){
}
My problem is that it's not possible to do 2 two orderByChild on the same fireBase query. How can i fix this ? please need help.
Assuming your data looks like this
activities
-JKjasjiji
date: 20151129
is_done: false
-Ykkjaso23
date: 20151128
is_done: true
-Jkaisjiij
date: 20151127
is_done: false
There are a few ways to go about this.
1) query for all activities where is_done: true then sort the results in code. This could be very inefficient depending on data set size. Sorting 1 Million in code would be bad.
2) Store the done activities in another node
activities
-JKjasjiji
date: 20151129
-Jkaisjiij
date: 20151127
done_activities
-Ykkjaso23
date: 20151128
3) Store the data in a format that will enable an 'and' type query
activities
-JKjasjiji
done_and_date: false_20151129
-Ykkjaso23
done_and_date: true_20151128
-Jkaisjiij
done_and_date: false_20151127
Then user .startAt and .endAt...
ref.orderByKey().startAt("true_20151128").endAt("true_20151129")
Would give return all activities that are done between the two specified dates.
Structuring your data can simplify your queries.
#Jay's answer is great. Here's another way to crack this nut, with the Bolt compiler.
Let's say you're building an expense reporting app, and your data structure goes as follows:
type User {
name: String;
uid: String;
}
type Expense {
id: String;
amount: Number;
uid: uid;
year: Number;
}
path /users/$uid is User;
path /expenses/$expense_id is Expense;
Now let's say you want to get all of the expenses by user 1 that happened in 2014. If this were SQL you could say:
SELECT *
FROM Expenses
WHERE uid == "1" AND year == 2014
With the Firebase SDK you would like to do something like this:
ref.child('expenses')
.orderByChild('uid')
.equalTo('1')
.orderByChild('year')
.equalTo('2014');
But, that's not possible. So what are we to do? Re-structure our data to fit this kind of query.
Rather than store all the expenses under the /expenses location, we can create an index for year with /expenses/year. This would look like:
path /expenses/$year/$expense_id is Expense
Now the query we wanted to do above can be acheived with:
ref.child('2014')
.orderByChild('uid')
.equalTo('1');
The structure you choose for your data will allow you to get the data as you need. You may find that you need to duplicate your data to do this. This is okay. And if you need to keep your data consistent across multiple locations, you can use client-side fanout.
I'm quite new to Android programming (very little programming experience). I want to make an app that will track Car maintenance. I would like users to be able to see their data (roughly) according to the following hierarchy:
Year (see total costs, maybe summarize categories)
--Month (month's costs)
----Maintenance Instance
------Details about the instance (what was done for what cost)
I don't have my data design finalized, but you can see the kind of data I'm trying to track. What approach would you suggest? Do I need to use SQLite? If so, would you recommend a hierarchy of tables or just one table that will be shown hierarchically through queries? Like I said, I'm new. I'd appreciate any pointers in the right direction.
In Android, you can use SharedPreferences to store simple data like global preferences (i.e. in your app you could store a currency flag as a preference to display currency as dollars or pounds) but for anything more complicated you should use SQLite. This tutorial is excellent and will get you started - http://www.vogella.com/tutorials/AndroidSQLite/article.html It seems like you could have one table with each row being a maintenance entry with columns for the date, cost and action carried out. You could then query the database by a date range to get the cost for that range or a list of action carried out in that range (e.g. per month or year). Each row would represent a separate maintenance event.
I recommend you use JSON, a very easy to use storage format. A typical JSON message you would store might look like the following:
{
"maintenance_data": [
{
"date": 1091029109,
"maintenance_details": "Drove car around while owner was gone"
},
{
"date": 1021234134,
"maintenance_details": "Ate cookies while on job"
},
{
"date": 1041023234,
"maintenance_details": "Ain't nobody got time for maintenance"
}
],
"car_id": 1234,
"owner_name": "Slick diddy"
}