Android Firebase : Update/Add record in Nested Array data - android

I am stuck in one case of firebase operation in android.
My Requirement :
I have table Named : "Values"
This value table contains following type of data.
{
"menu": [
{
"category": "cocktails",
"product": [
{
"id": "123",
"name": "test1"
},
{
"id": "456",
"name": "test2"
}
]
},
{
"category": "vodka",
"product": [
{
"id": "789",
"name": "test3"
},
{
"id": "901",
"name": "test4"
}
]
}
]
}
Now, I want to update id : 123 with name = "test5" , How to update this nested array object
in firebase database in android?
I tried following but it update/add Entire menu array not perticular product array object.
I just want to update in product array object.
Following are the code that i tried, but it update all menu array.
val listPorduct = ArrayList<HashMap<String, Any>>()
for ((i, product) in productList.withIndex()) {
var productMap = HashMap<String, Any>()
productMap = hashMapOf(
"id" to "123",
"name" to "test5")
listPorduct.add(productMap)
}
val map = hashMapOf<String, Any>()
map.put("category", list[position].category)
map.put("product", listPorduct)
repository.getTabs().update("menu", FieldValue.arrayUnion(map))
if i am try with
repository.getTabs().update("menu/product", FieldValue.arrayUnion(map))
or
repository.getTabs().update("menu.product", FieldValue.arrayUnion(map))
then getting issue / or dot not allowed. i have latest firebase gradle file.
How update particular position of product object?
Please anyone can help me to solve out this?
Image of firebase database.

The solution to this problem can be found in my answer from the following post:
firestore -- Add element in a field in hashmap
There is a slightly smaller difference. However, for your use-case, please note that the document that you gave us as an example contains a property named menu which is of type array. In this array, you have added some objects that contain two properties, a String property named category and an array named product. This array contains in term two other properties, one is the id and the other one is the name, both being of type String.
None of those arrays can be updated using FieldValue.arrayUnion(map). The only option that you have is to get the menu array as a list of HashMap<String, Any>. Once you have this map, you can simply iterate through it and get the desired data.
So to update the value of a property inside a Map, you should first get the map, do the changes and put it back. In the end, after you've done all the necessary changes, write the document back to Firestore.
Edit:
According to your comment:
In my case I have more than 5000 records in a list with a nested array.
It's hard to believe that you can nest 5000 elements into a single document because it might not fit since the maximum size for a document is 1 MiB (1,048,576 bytes). Please see usage and limits. So nesting 5000 objects into an array isn't a solution at all. In this case, the single solution that you have is to use a sub-collection and add each item from the array as a document. In this case, there are no limitations.
As a conclusion, the only highly scalable way to store an unknown large list of items is using documents in a collection. Array type fields do not scale for lists the are constantly growing because the items will eventually exceed that (1 MiB), which will obviously cause problems in the future.

Related

Firebase RTDB: How to filter child events based on a nested field?

Given that every entry in my Firebase Realtime Database has a version field that represents the timestamp it was last edited, how can I filter them by their version such that only child events that are newer than X are delivered?
val listener = object : ChildEventListener {
// Not relevant
}
val ref = database.getReference("exercises").child("userId")
ref.addChildEventListener(listener)
// TODO: ref.filter(version>localVersion)
For context as to why Im looking to do this. There are very many entries, and while Id like to know whenever any of them change, observing all of them at all times results in too big of a memory footprint (>150 mb).
Json representation of a data model (exercise):
{
"details" : {
"category" : "LIFT",
"equipment" : "CABLE_MACHINE",
"muscles" : [ "BACK" ],
"name" : "Row in Cable Machine",
"status" : "AVAILABLE"
},
"id" : "1",
"source" : "CUSTOM",
"version" : 1648446264560 // This is the field Id like to filter on.
}
How can I filter them by their version such that only child events that are newer than X are delivered?
Since your version filed is a number, to get only the objects newer than a particular value you can use the Query#startAt() function, which:
Creates a query constrained to only return child nodes with a value greater than or equal to the given value, using the given orderBy directive or priority as default.
Or Query#startAfter() function that:
Creates a query constrained to only return child nodes with a value greater than the given value, using the given orderBy directive or priority as default.

How do you change a field in array of maps in firestore? [duplicate]

I am stuck in one case of firebase operation in android.
My Requirement :
I have table Named : "Values"
This value table contains following type of data.
{
"menu": [
{
"category": "cocktails",
"product": [
{
"id": "123",
"name": "test1"
},
{
"id": "456",
"name": "test2"
}
]
},
{
"category": "vodka",
"product": [
{
"id": "789",
"name": "test3"
},
{
"id": "901",
"name": "test4"
}
]
}
]
}
Now, I want to update id : 123 with name = "test5" , How to update this nested array object
in firebase database in android?
I tried following but it update/add Entire menu array not perticular product array object.
I just want to update in product array object.
Following are the code that i tried, but it update all menu array.
val listPorduct = ArrayList<HashMap<String, Any>>()
for ((i, product) in productList.withIndex()) {
var productMap = HashMap<String, Any>()
productMap = hashMapOf(
"id" to "123",
"name" to "test5")
listPorduct.add(productMap)
}
val map = hashMapOf<String, Any>()
map.put("category", list[position].category)
map.put("product", listPorduct)
repository.getTabs().update("menu", FieldValue.arrayUnion(map))
if i am try with
repository.getTabs().update("menu/product", FieldValue.arrayUnion(map))
or
repository.getTabs().update("menu.product", FieldValue.arrayUnion(map))
then getting issue / or dot not allowed. i have latest firebase gradle file.
How update particular position of product object?
Please anyone can help me to solve out this?
Image of firebase database.
The solution to this problem can be found in my answer from the following post:
firestore -- Add element in a field in hashmap
There is a slightly smaller difference. However, for your use-case, please note that the document that you gave us as an example contains a property named menu which is of type array. In this array, you have added some objects that contain two properties, a String property named category and an array named product. This array contains in term two other properties, one is the id and the other one is the name, both being of type String.
None of those arrays can be updated using FieldValue.arrayUnion(map). The only option that you have is to get the menu array as a list of HashMap<String, Any>. Once you have this map, you can simply iterate through it and get the desired data.
So to update the value of a property inside a Map, you should first get the map, do the changes and put it back. In the end, after you've done all the necessary changes, write the document back to Firestore.
Edit:
According to your comment:
In my case I have more than 5000 records in a list with a nested array.
It's hard to believe that you can nest 5000 elements into a single document because it might not fit since the maximum size for a document is 1 MiB (1,048,576 bytes). Please see usage and limits. So nesting 5000 objects into an array isn't a solution at all. In this case, the single solution that you have is to use a sub-collection and add each item from the array as a document. In this case, there are no limitations.
As a conclusion, the only highly scalable way to store an unknown large list of items is using documents in a collection. Array type fields do not scale for lists the are constantly growing because the items will eventually exceed that (1 MiB), which will obviously cause problems in the future.

Does whereEqualTo support HashMap equality?

The whereEqualTo API can take Any as its argument. Does this mean that I can pass it a HashMap<K, V> and it will compare its matching fields with that of a field of map type in the Firestore database or do I have to manually compare each property of the map?
I've build a query like this one
collection.whereEqualTo("meta", hashMapOf( // <-- using full hash-map for matching
"user" to "JD",
"name" to "John"
))
where meta is a map-type field with two key/value pairs.
The document I'm trying to match has this structure:
{
"createdOn": as timestamp
...other properties
"meta": as map
{
"user": "JD", as string
"name": "John" as string
}
}
The criteria I use should yield some results but it doesn't (without crashing) so I was wondering whether I made a mistake somewhere else or is this type of a query simply not supported? The result is empty.
I might also be searching only for the name property with a simpler query like this one to find all Johns
collection.whereEqualTo("meta", hashMapOf( // <-- using parcial hash-map for matching
"name" to "John"
))
Will it match only name fields or does it require a full-map?
I mean, should the previous query work or do I need to rewrite as this?
collection
.whereEqualTo("meta.user", "JD")
.whereEqualto("meta.name", "John")
Firestore can compare items of a map in your client code with a map in a document. But the maps must be completely equivalent, so you must specify all properties in your code. So something like this should work:
collection.whereEqualTo("meta", hashMapOf( // <-- using parcial hash-map for matching
"user" to "JD",
"name" to "John"
))
If you can't get this to work, edit your question to include a screenshot of the document you think this should match and I'll have another look.
There is no way specify partial map matches for a field, so if that's what you need, you'll indeed need to add separate conditions for each nested field.

how can get data dynamically and parse any specific key and value without knowing name?

I am working on an module in which i have to get the json data and get array name (which is table name of android database) and all keys and value of array(which is keys=columns & values=data of columns) and array name(table name) and their related data can be more than 1 or in 20s or more . i do not know how to implement it because i have not done this kind of code before..please help me to solve this problem.
my json code is like.. every array name would be different this is an example only but data will coming like this
{
"MSG": "OK",
"data": [
{
"strPrimaryKey": "iDeviceAppId",
"Device_App": [
{
"strAppName": "NI Data Dashbard",
"isDeleted": "0",
"strVersion": "2.3.0",
"dtCreateDate": "2018-04-09",
"iDeviceAppId": "0",
"dtUpdateDate": "2018-04-13",
"iOnHomeScreen": "1"
}
]
}
]
}
You can parse the JSON you received into a map and then traverse the map to get what you need.

How the Sugar Record model will be created for given JSON

I have following JSON and I want to create Sugar Record Class for it to store it in a database but I am not able to figure out weather I will need multiple model class or single would be enough please help me with this.
{
"command": "AN",
"tripId": 0,
"tripData": {
"DeviceId": "30050",
"DispatcherId": 1,
"PaxLimit": 50,
"DriverId": 6,
"Trips": [{
"Stops": [{
"Id": 1,
"ScheduleTime": "06:00"
}, {
"Id": 5,
"ScheduleTime": "07:00"
}],
"RouteId": 5,
"ToStopId": 5,
"TripId": 123,
"FromStopId": 1
}]
}
}
It really depends on the object you want to store. Because Sugar doesn't support 1 to many relationships. I see your Trips and Stops attributes (in the JSON) are both arrays in the JSON. It is not possible to save that in the Sugar database. Because you cannot store a List with Sugar.
You can choose for yourself if you would like one single class containing all attributes that are in the JSON object. The other options is to use Nested Classes.
It doesn't matter what option you choose because you can get the data out of the JSON and put it in the right Class. The only thing that is important is that you can't use Lists in a Class.
So it really is your own choice if you use one or multiple classes.

Categories

Resources