Retrieve integer from Firebase child - firebase

I am trying to implement a counter for deals in my app. i am trying to recall the last integer written to the child e.g. deal number 10. i can successfully write a manually inputted value into firebase however i cannot retrieve the initial value.
i am using the following
dealnumRef = FirebaseDatabase.getInstance().reference
val numberRef = dealnumRef.child("Total_deals").orderByChild("deal_number")
val dealnumEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (ds in dataSnapshot.children) {
val deal_num =
ds.child("deal_number_cars").getValue()
d("current deal number",deal_num.toString())
val new_deal_num = deal_num + 1
the issue i have is that currently deal_num is pulling through as Any?. If i insert String::class.java into getvalue()it will bring it back as a string. But I need to keep it as an Integer to compute new_deal_num because new_deal_num will need to be written to the database and increment the deal_number to 11 as an example.
how do i extract deal_num as an integer?
I have checked available answers, but those indicate to convert to string. This would not work in my example, because i need to increment the deal number and hence keep it as an integer.

You can get the correct type from Firebase by passing its class into getValue(..).
So:
val deal_num = ds.child("deal_number_cars").getValue(Long.class)
If you're storing a number in deal_number_cars in the database, this will get that value as a long.

The Full correction to the above is as follows:
dealnumRef = FirebaseDatabase.getInstance().reference
val numberRef = dealnumRef.child("Total_deals").orderByChild("deal_number_cars")
val dealnumEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (ds in dataSnapshot.children) {
val deal_num =
ds.getValue(Long::class.java)!!
d("current deal number",deal_num.toString())
val new_deal_num = deal_num + 1
You also have to make sure that you data model class is set as Long. i originally had it set as Int which created a small problem but was easily resolved.

Related

Android: Why is Room so slow?

I am working on a simple database procedure in Kotlin using Room, and I can't explain why the process is so slow, mostly on the Android Studio emulator.
The table I am working on is this:
#Entity(tableName = "folders_items_table", indices = arrayOf(Index(value = ["folder_name"]), Index(value = ["item_id"])))
data class FoldersItems(
#PrimaryKey(autoGenerate = true)
var uid: Long = 0L,
#ColumnInfo(name = "folder_name")
var folder_name: String = "",
#ColumnInfo(name = "item_id")
var item_id: String = ""
)
And what I am just trying to do is this: checking if a combination folder/item is already present, insert a new record. If not, ignore it. on the emulator, it takes up to 7-8 seconds to insert 100 records. On a real device, it is much faster, but still, it takes around 3-4 seconds which is not acceptable for just 100 records. It looks like the "insert" query is particularly slow.
Here is the procedure that makes what I have just described (inside a coroutine):
val vsmFoldersItems = FoldersItems()
items.forEach{
val itmCk = database.checkFolderItem(item.folder_name, it)
if (itmCk == 0L) {
val newFolderItemHere = vsmFoldersItems.copy(
folder_name = item.folder_name,
item_id = it
)
database.insertFolderItems(newFolderItemHere)
}
}
the variable "items" is an array of Strings.
Here is the DAO definitions of the above-called functions:
#Query("SELECT uid FROM folders_items_table WHERE folder_name = :folder AND item_id = :item")
fun checkFolderItem(folder: String, item: String): Long
#Insert
suspend fun insertFolderItems(item: FoldersItems)
Placing the loop inside a single transaction should significantly reduce the time taken.
The reason is that each transaction (by default each SQL statement that makes a change to the database) will result in a disk write. So that's 100 disk writes for your loop.
If you begin a transaction before the loop and then set the transaction successful when the loop is completed and then end the transaction a single disk write is required.
What I am unsure of is exactly how to do this when using a suspended function (not that familiar with Kotlin).
As such I'd suggest either dropping the suspend or having another Dao for use within loops.
Then have something like :-
val vsmFoldersItems = FoldersItems()
your_RoomDatabase.beginTransaction()
items.forEach{
val itmCk = database.checkFolderItem(item.folder_name, it)
if (itmCk == 0L) {
val newFolderItemHere = vsmFoldersItems.copy(
folder_name = item.folder_name,
item_id = it
)
database.insertFolderItems(newFolderItemHere)
}
}
your_RoomDatabase.setTransactionSuccessful() //<<<<<<< IF NOT set then ALL updates will be rolled back
your_RoomDatabase.endTransaction()
You may wish to refer to:-
https://developer.android.com/reference/androidx/room/RoomDatabase
You may wish to especially refer to runInTransaction

Testing and Mocking ScalaGraph with gremlin

I have a Service class that i am trying to unit test. The service class is as follows -:
class BtoService #Inject()(db: GrDbConnection,
businessService: BusinessService,
vertexIdGenerator: VertexIdGenerator) {
def updateBto(id: String, updateBTOReq: UpdateBTORequest) = {
implicit val g = db.g
val btoVertex = g
.V(
vertexIdGenerator.vertexId(VertexLabels.BTO, id, PropertyLabels.BTO_ID))
.headOption() match {
case Some(value) => value
case None => throw BtoDoesNotExistException(s"BTO $id Does not exists")
}
So while testing this class, i create a mock of injected services(BusinessService, GrDbConnection) -:
val db: GrDbConnection = mock[GrDbConnection]
val businessService: BusinessService = mock[BusinessService]
val vertexIdGenerator: VertexIdGenerator = mock[VertexIdGenerator]
val btoService: BtoService = new BtoService(db, businessService, vertexIdGenerator)
val g : ScalaGraph = EmptyGraph
.instance()
.asScala()
btoService.updateBto("101",updateBTORequest)
Mockito.when(db.g).thenReturn(g)
The GrDbConnection.scala has the defined db.g -:
val g: ScalaGraph = EmptyGraph
.instance()
.asScala
.configure(_.withRemote(connection))
here connection has the necessary details to connect to the actuall db.
Since i can return an empty scala graph using Mockito.when().thenReturn(), i preferred not to use .configure() option in my test class.
My real problem that i face is that, i am not able to add a vertex to the test graph, I need to add a btoModel as the vertex to the graph since, in service class :
val btoVertex = g.V(vertex......()).headOption() - returns a GremlinScala.Aux[scala.vertex, Hnil]
How do i proceed with that?
please contact me at - nilay0016#gmail.com for more info.

Kotlin Map<String, List<Object>> values are changed after toSortedMap call

I got such a map
Map<String, List<Object>>
when I use
map.toSortedMap(comparator)
and comparing values by keys I got sorted map but amount of objects in each value list is also changed (reduced). It's super strange. Under the hood toSortedMap method creates TreeMap with the given comparator, I don't know TreeMap internals but I assume that any map should not change values but only manipulate with the keys. Is this something that is ok for TreeMap or is it a bug in Kotlin library?
Edit
Code I get this issue on:
val categoriesKeys = listOf("key1", "key2", etc)
val categoriesKeysOrdersMap = mapOf("key1" to 0, "key2" to 1, etc)
val model = listOf(MyModel(..), MyModel(..), etc)
val categoryKeyToModelsMap = categoriesKeys
.asSequence()
.map { key ->
key to model.filter {
it.categories?.contains(key) == true
}
}
.filter { it.second.isNotEmpty() }
.toMap()
.toSortedMap(compareBy { categoriesKeysOrdersMap[it] })
On toMap step I have the map I want but not sorted, but after toSortedMap my data is messed up. Comparator compares by int value from categoriesKeysOrdersMap using key from category.

Getting min. value from list where column name in string

Tb_AgentRates objrates = db.Tb_AgentRates.Where(z => z.AgentId == objcity).OrderBy(z => z.Rates).Min();
I want min. value of rates. But problem is that Rate Column in varchar that's why it's not showing result.
I assume that Min-Value means that this is actually a number which is stored as string. You should fix that by storing it as int (or whatever numeric type it is).
Until you've fixed the type issue you can use for example int.Parse or decimal.Parse:
Tb_AgentRates objrates = db.Tb_AgentRates
.Where(z => z.AgentId == objcity)
.Min(z => decimal.Parse(z.Rates));
You cant parse directly in Linq expression itself. Instead you can use like this
var query = (from row in db.Tb_AgentRates.AsEnumerable()
where row.AgentId== objcity
let range = ParseInt32(row.Rates)
select range).ToList();
var minValue = query.Min();
and you declare your method like this
public static int? ParseInt32(string str)
{
int result = 0;
return Int32.Parse(str);
}

How use a variable name to point different data types with the same name?

I have 2 List one stores the name of filterable columns(of type DropDown) and another store the values to load in those filterable columns.
List<string> filterableFields = new List<string>() { "A_B", "C_D", "E_F" };
List<string> AB, CD , EF;
Now at the run time I get the data from web service and I have written a function to to extract values for these filterable fields and store the values to 2nd List.
private void prepareListForFilterableColumns(XDocument records)
{
foreach (var currentField in filterableFields)
{
var values = (from xml in records.Descendants(z + "row")
let val = (string)xml.Attribute("ows_" + currentField.Replace("_", "_x0020_"))
where val != ""
orderby val
select val
).Distinct();
switch (currentField)
{
case "A_B": AB = values.ToList(); break;
case "C_D": CD = values.ToList(); break;
}
}
}
Now I was thinking that instead of hard coding the assignment in swtich case block, If I could just use the first List name "A_B" and replace "_" from it to point to my 2nd List and assign values.ToList() to it.
I understand that c# is a static language, So not sure if we can achieve this, but IF I can it will make my function generic.
Thanks a lot in advance for time and help.
Vishal
You could use a dictionary of lists of strings instead of 3 lists to store the values.
Dictionary<string, List<string>> val lists = new Dictionary<string,List<string>>();
And make the keys of the dictionary equal to the filterables: "AB", "CD",..
then, instead of AB you would use valLists["AB"] and could then reference reach list based on a string key.
The other option would be to use reflection but that would be slower and unnecessarily a bit more complicated.

Resources