Firestore use contains on multiple fields - android

I have an upcoming video games app. A game release can come out on multiple platforms. I heard that firestore is much more flexible than firebase real time database on how you can retrieve your data. I'm stuck on how can I check if my game release documents in my release collection contains the user chosen platforms, so the app can show the games coming out on his platforms.
This is what I currently have
platforms is a list of Integer which contains platforms ids
databaseReference.collection(getRegionNode())
.whereEqualTo("m_y", monthFilter)
.whereArrayContains("platforms", platforms)
.orderBy("date", Query.Direction.ASCENDING).get().addOnCompleteListener(listener);
Here's an example of a game release document:
1369: {
"src": "Images/dead.png",
"name": "red dead 2",
"date": 2018-10-26,
"region": worldwide,
"platforms": "[12, 13, 54]"
}
Let's say for example, user wants to only be shown platform 12 and 13 games, I want a query that checks and retrieves all releases documents where 12 and 13 are in their platforms list. Thank you!

Firestore Query's whereArrayContains(String field, Object value):
Creates and returns a new Query with the additional filter that documents must contain the specified field, the value must be an array, and that the array must contain the provided value.
According to your comments, your platforms object that is passed as the second argument to this method is of type array. What you are actually doing, you are searching in the platforms property which is of type array for an array, which is not possible since the platforms array in your database contains numbers:
"platforms": "[12, 13, 54]"
And not arrays. A query like this:
databaseReference.collection(getRegionNode())
.whereEqualTo("m_y", monthFilter)
.whereArrayContains("platforms", 12) //Passed a number as the second argument
.orderBy("date", Query.Direction.ASCENDING).get().addOnCompleteListener(listener);
Will work fine because we are searching within the platforms array for a number. Please also note, if you intend to use this king of query, an index is required. For how to create an index, please see my answer from this post.
Even if you using the above query, you can filter your items using only one whereArrayContains() method call. If you will use more than one, the following error will occur:
Caused by: java.lang.IllegalArgumentException: Invalid Query. Queries only support having a single array-contains filter.
If you need to filter on more than one platform, you'll need to change the logic of structuring your database by creating a property for each individual platform that you have and chain whereEqualTo() method calls. I know it sounds a little weird but this is how Cloud Firestore works.
Your schema should like this:
1369: {
"src": "Images/dead.png",
"name": "red dead 2",
"date": 2018-10-26,
"region": worldwide,
"platformsOne": 12,
"platformsTwo": 13,
"platformsThree": 54
}
To find all the games for platform 12, 13 and 54, you should use a query that looks like this:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
Query query = rootRef.
.whereEqualTo("platformsOne", 12)
.whereEqualTo("platformsTwo", 13)
.whereEqualTo("platformsThree", 54);

Related

How to model a Firebase Database in UML diagrams?

I have a project in android so I decided to make a Quiz app, and I used Firebase in it.
But I also need to design UML diagrams for this project and I was wondering if I can do it since Firebase is a Table-less database.
The Firebase databases, be it its realtime database or the cloud firestore, are document-oriented NoSQL databases. There are indeed no tables, just collections of documents, where each document is a JSON-like structure, and documents could contain other embedded collections or documents.
In theory, each document in a collection could be completely different from all the others. In this case, an UML class-diagram would make no sense since classes suppose common properties and behaviors.
db.collection("ouch"): // Not recommended
[ {name: "Spiderman"},
{size: "XXL", item: "T-Shirt},
{date: "July 4 1776", event:"independence day"} ]
In practice, however, documents in a collection are in general a set of very similar objects, or at least related objects. May be one object of the set has a couple of properties more, or a couple of properties less. But they represent the same kind of things:
db.collection("users"): // example 1, small variations
[ { id: "AL", first: "Ada",last: "Lovelace"},
{ id: "JSMITH", last: "Smith", first: "Joe", lastLogin:"2021-07-10"} ]
db.collection("shopItems"): // example 2, more variations but common ground
[ { id: 123, type: "Book", title: "The definitive guide to Firebase", author:"L.Moroney", price: 34.23 },
{ id: 124, type: "Record", title: "Get lucky", artist: "Daft Punk", price: 16.20}
{ id: 125, type: "Shirt", brand: "Seidensticker", model:"Classic", size: "XL", color:"white", price: 65.00 } ]
In this case, you may perfectly use UML class diagrams, because UML is not table based, but class based:
A class represents a kind of things. In reverse engineering you'd usually start with the known collections.
Small structural differences between documents of a same kind would be represented in the UML class diagram either with "optional" properties (i.e. multiplicity [0..1]) (see lastLogin in the users example).
More substantial differences between documents having some common ground, would usually be modeeled with more specialized classes (see the shopItems example, where we can guess a class ShopItem and specializations thereof such as BookItem, RecordItem, TextileItem).
The challenge in the modelling, is to understand the embedded documents and sub-collections. These are often sign other associated classes (or composed classes).
In principle, the UML class-diagram would not be used only for the database (data only), but it would be used to design the objet model of your application (data and behavior) independently of your database. The model could then help you to design the database based on the kind of objects needed to address you' user's needs.

Firebase dump json data

I'm no back-end developer. So perspective is always appreciated.
I have written a script which requests from an API and creates this huge JSON file I want to save in firebase, how can I accomplish this? And would it be possible to filter this json with python for example; when I add region=eu in the url this returns the objects which have Europe as region or do I absolutely need to request the entire json file and parse in my code (java android) ?
Since there are a few parts to your question:
You can save JSON to Firebase and the data will be mapped to child locations:
Using PUT, we can write a string, number, boolean, array or any JSON object to our Firebase database...When a JSON object is saved to the database, the object properties are automatically mapped to child locations in a nested fashion.
https://firebase.google.com/docs/database/rest/save-data
And for your next question:
And would it be possible to filter this json with python for example; when I add region=eu in the url this returns the objects which have Europe as region
Looks like you should be able to jimmy something together with Firebase's filters, startAt and endAt:
We can combine startAt and endAt to limit both ends of our query.
https://firebase.google.com/docs/database/rest/retrieve-data#section-rest-filtering
For your example you might do something like this:
curl 'https://yourfirebase.firebaseio.com/yourendpoint.json?orderBy="$REGION_NAME"&startAt="EU"&endAt="EU"&print=pretty'
...or do I absolutely need to request the entire json file and parse in my code (java android) ?
The facts that JSON objects are stored hierarchically in Firebase and that you can filter based on those object values makes me think you do not, in fact, have to request the entire JSON file. However, I don't have personal experience with this particular aspect of Firebase, so give it a shot!
As #ackushiw mentions in the comments, you can also use the equalTo query (https://firebase.google.com/docs/reference/js/firebase.database.Query#equalTo):
curl 'https://yourfirebase.firebaseio.com/yourendpoint.json?orderBy="$REGION_NAME"&equalTo="EU"&print=pretty'
It really depends on how you are structuring your JSON. It's generally recommended to make your JSON tree as shallow as possible since all children are loaded when you have a matching query.
FIREBASE DATA:
{
"-id1": {
"region": "eu" // bear in mind queries are case sensitive
"title": "Foo"
"nested": {
"city": "berlin"
}
},
"-id2": {
"region": "other"
"title": "Bar"
"nested": {
"city": "berlin"
}
},
"-id3": {
"region": "eu"
"title": "Baz"
"nested": {
"city": "paris"
}
}
}
Querying with (using the Android API)
.orderByChild("region").equalTo("eu")
would return "-id1" and "-id3"
with
.orderByChild("nested/city").equalTo("berlin")
would return "-id1" and "-id2"
The REST API Returns Unsorted Results: JSON interpreters do not enforce any ordering on the result set. While orderBy can be used in combination with startAt, endAt, limitToFirst, or limitToLast to return a subset of the data, the returned results will not be sorted. Therefore, it may be necessary to manually sort the results if ordering is important.
If you're using a more complex structure I recommend watching this video
https://www.youtube.com/watch?v=vKqXSZLLnHA
I'd also recommend using the firebase library for Android
https://firebase.google.com/docs/android/setup
And Firebase-UI, It does a lot for you.
https://firebaseopensource.com/projects/firebase/firebaseui-android/

Google Fit API - Get time of exercise

I am trying to create an app using Google Fit Api and i am trying to get the total time of exercise (supposed that the exercise is walking) for the user. What i want basically is to get the value marked in below image :
Google Fit Time Screenshot
I was thinking to work with sessions (https://developers.google.com/fit/android/using-sessions) but i prefer to skip this if there is already something provided by Google. I know how to get the daily steps/calories/distance but i am not able to find anything to get the daily exercise time.
Let me describe what I found so far, but there is one issue left...
You can use the aggregate api and group by activity type. Here is an example with daily bucketing:
POST https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate
{
"aggregateBy": [
{
"dataSourceId": "derived:com.google.activity.segment:com.google.android.gms:merge_activity_segments"
}
],
"endTimeMillis": "1481788800000",
"startTimeMillis": "1481702400000",
"bucketByTime": {
"period": {
"timeZoneId": "America/Los_Angeles",
"type": "day",
"value": 1
}
}
}
The call will return a number of records, each containing three values: activity type, duration in milliseconds, and number of segments. You can find the activity types at: https://developers.google.com/fit/rest/v1/reference/activity-types. You can add up the milliseconds for the activity types you are interested in.
Now, the issue - I have seen examples of mismatch of activity types between the API and Fit app. I don't know how widespread the mismatch is. See my question: Getting active time from Google Fit Rest API.

Firebase data flattening

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.

How Should I Store Data for My Android App?

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"
}

Categories

Resources