Kotlin Realtime Firebase Post set autoincrement ID to database - firebase

I would like to save an Item to Firebase. When I save one Item, then my structure looks like i want to look, but I have problem with ID:
Trips
-My6qIbSx5dnSy2yScAr
date: "Feb 20, 2022 12:00:00 AM"
distance: "25"
id: 0 <- here I want autoincrement ID
name: "Test ONE"
-My6qUykRSjuxu_MnyO_
date: "Feb 20, 2022 12:00:00 AM"
distance: "25"
id: 0 <- here I want autoincrement ID
name: "Test TWO"
I cannot put to field id my incremented id from above, which Firebase is adding, after putting Item to database.
I'm using api Firebase and my code looks like this :
Service:
#POST("${FirebaseFactory.BASE_URL}/Trips.json")
suspend fun saveTrip(#Body trip : Item) {
}
And ViewModel:
val testPutTrips = client.saveTrip(Item("Test ONE", "25", "Feb 20, 2022 12:00:00 AM", here i'm nothing passsing, because my Model has autoincrement, but it doesnt work and always put me 0))
Model:
#Entity(tableName = "trip")
data class Item(
#ColumnInfo(name = "name") val name: String,
#ColumnInfo(name = "distance") val distance: String,
#ColumnInfo(name = "date") val date: Date,
#PrimaryKey(autoGenerate = true) val id: Int = 0)
Is it possible to put incremented ID to filed?

From the Firebase documentation on appending data to a list:
You can use the reference to the new data returned by the push() method to get the value of the child's auto-generated key or set data for the child. Calling getKey() on a push() reference returns the value of the auto-generated key.
In code it'd look something like:
val newRef = mDatabase.child("Trips").push();
yourObject.id = newRef.key;
newRef.setValue(yourObject);

Related

Is there a way to paginate related data in sqlmodel on the frontend

The sqlmodel docs gives an example of two classes
class Team(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(index=True)
headquarters: str
heroes: List["Hero"] = Relationship(back_populates="team")
class Hero(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(index=True)
secret_name: str
age: Optional[int] = Field(default=None, index=True)
team_id: Optional[int] = Field(default=None, foreign_key="team.id")
team: Optional[Team] = Relationship(back_populates="heroes")
I could get a Team object using the following code example
def get_team():
with Session(engine) as session:
statement = select(Team).where(Team.name == "avengers")
result = session.exec(statement)
avengers = result.one()
return avengers
and doing avengers.heroes should return a list of all heroes related to that object but What if the list contains thousands of items? is there a way to paginate this without having to make a separate query to the heroes table by myself?
To do this, you have to work with the underlying SQLAlchemy library, which you can do using the sa_relationship_kwargs argument to Relationship.
As mentioned in this answer, if you specify the relationship as dynamic, you can then paginate it. Using SQLModel, it looks something like this:
class Team(SQLModel, table=True):
...
heroes: List["Hero"] = Relationship(
back_populates="team",
sa_relationship_kwargs={"order_by": "Hero.name", "lazy": "dynamic"},
)
# When calling it
first_ten_heroes = team.heroes[:10] # or team.heroes.limit(10)

Flask restx api model not showing model data

I have a model as follows:
class Menu(db.Model):
itemId = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(255),index=True)
price = db.Column(db.Numeric)
description = db.Column(db.String(255),index=True)
image = db.Column(db.LargeBinary)
restaurantId = db.Column(db.Integer, db.ForeignKey('restaurants.id'))
createdOn = db.Column(db.DateTime,server_default=db.func.now())
status = db.Column(db.Integer,server_default="1")
orders = db.relationship('Orders', backref='menu', lazy='dynamic')
def __repr__(self):
return '<Menu of restaurant id {}>'.format(self.restaurantId)
And I have the following api model corresponding to it:
menu_model = api.model('Menu',
{'itemId':fields.Integer(),
'name':fields.String(),
'price':fields.Float(),
'description':fields.String(),
'restaurantId':fields.Integer(),
'createdOn:':fields.DateTime(),
'status':fields.Integer()})
The problem is that even though the createdOn values are correctly generated on DB side, the response shows the createdOn field as null. What could be the reason?
"menu":
{
"itemId": 1,
"name": "Menu item",
"price": 30.0,
"description": "Menu item description",
"restaurantId": 1,
"createdOn:": null,
"status": 1
}
this will accept the desired output. The first parameter is a label, not part of the json
menus = api.model(
"menu_item",
{
'itemId':fields.Integer(),
'name':fields.String(),
'price':fields.Float(),
'description':fields.String(),
'restaurantId':fields.Integer(),
'createdOn:':fields.DateTime(),
'status':fields.Integer()
},
)
menu_model = api.model(
"Menu",
{
"menu": Nested(menus),
},
)

sum and group by do not work in android roomdatabase Kotlin

I have a roomdatabase with 4 tables, I want to use GROUP BY and also SUM both in ONE query.
so what I had done till now:
#Query("SELECT *, SUM(increase) FROM transactions GROUP BY user_id")
fun groupBy(): LiveData<List<Transactions>>?
But SUM doesnt work(It shows the first increase by user_id.
For instanse: I have 2 users named MAX and Amir with user id 1 and 2
Amir(userId 1) submit 100$ increase and again 50$ increase.
Max(userId2) submit 80$ increase and again 10$ increase.
Please look at the result:
D/TAG: groupBy: 1 100
D/TAG: groupBy: 2 80
It supposed to show:
D/TAG: groupBy: 1 150
D/TAG: groupBy: 2 90
one point:
I have a field in database that named trans_id which stands for transactionId.
Each time I submit increase or decrease or anything else thet related to user and money my app automaticly genereates one id and it is transactionId each time it autmaticly generate transactionId but It is not as same as last one.
Where I use It?
When I want to get all user's transactions
Function where I read data from(in user list fragment):
private fun groupBy() {
mUserListViewModel.groupBy()?.observe(viewLifecycleOwner, {
mUserListViewModel.group.value = it
it.forEach {
Log.d("TAG", "groupBy: ${it.userId} // ${it.increase}")
}
})
}
My viewModel:
val group = MutableLiveData<List<Transactions>>()
fun groupBy(): LiveData<List<Transactions>>? {
return mTransactionDAO.groupBy()
}
Data class:
data class Transactions(
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "trans_id")
var transId: Long = 0L,
#ColumnInfo(name = "user_id", index = true) // <<<<< best to have an index on the column, not required
var userId: Long?,
#ColumnInfo(name = "create_date")
var createDate: String?,
#ColumnInfo(name = "bank_id")
var bankId: Long?,
#ColumnInfo(name = "description")
var description: String?,
#ColumnInfo(name = "increase")
var increase: String?,
#ColumnInfo(name = "decrease")
var decrease: String?,
#ColumnInfo(name = "loan_number")
var loanNumber: String?,
#ColumnInfo(name = "total")
var total: String?,
#ColumnInfo(name = "type")
var type: String?,
#ColumnInfo(name = "loan_id")
var loanId: Long?
)
My database
If you need more code, let me know in comments section
When you use group by clause then column name is required remove * and add specific column name like this.
#Query("SELECT user_id, SUM(increase) FROM transactions GROUP BY user_id")
fun groupBy(): LiveData<List<Transactions>>?
Your code does not read the summed increase but the column increase of your table because you use * which selects all the columns.
The correct way to write the query is:
#Query("SELECT user_id, SUM(increase) AS increase FROM transactions GROUP BY user_id")
fun groupBy(): LiveData<List<userTotals>>?
so that you get 2 columns: the user_id and the the total of increase aliased as increase.
You also need to create a new class for the results of the query:
data class userTotals(val user_id: Long?, val increase: Long?)

map duplicates key value pair if not present

Following is my structure definition:
type test struct{
Title string
State string
Counts int
}
I want to map struct object members in following way
map[Title:map[State:Counts]]
This is the code which successfully do so
func main() {
r := make(map[string]map[string]int)
r1 := make(map[string]int)
var ts []test
ts = append(ts, test{Title: "Push 1",
State: "Active",
Counts: 20})
ts = append(ts, test{Title: "Push 1",
State: "InActive",
Counts: 20})
ts = append(ts, test{Title: "Push 1",
State: "Checked",
Counts: 20})
ts = append(ts, test{Title: "Push 1",
State: "Active",
Counts: 23})
ts = append(ts, test{Title: "Push 2",
State: "Active",
Counts: 20})
ts = append(ts, test{Title: "Push 2",
State: "InActive",
Counts: 23})
for _, t := range ts {
r1[t.State] = t.Counts
r[t.Title] = r1
}
fmt.Println("struct: ", ts)
fmt.Println("map: ", r)
}
Problem I am facing is Title "Push 2" which does not have a State: Checked is been appended with Count value of previous object.
Following output is as follows
struct: [{Push 1 Active 20} {Push 1 InActive 20} {Push 1 Checked 20} {Push 1 Active 23} {Push 2 Active 20} {Push 2 InActive 23}]
map: map[Push 1:map[Active:20 Checked:20 InActive:23] Push 2:map[Active:20 Checked:20 InActive:23]]
Code I compiled is in go playground.
r := make(map[string]map[string]int) only creates a single map, it has no entries.
r1 := make(map[string]int) also only creates a single map to count states, but you don't need only one, you need a separate one for each distinct title.
So instead of creating that single r1, create inner maps on demand. Range over your structs, and when there is no inner map for its title, then create one and store it in the outer r map.
Like this:
for _, t := range ts {
counts := r[t.Title]
if counts == nil {
counts = make(map[string]int)
r[t.Title] = counts
}
counts[t.State]++
}
Note that the counting operation may simply be counts[t.State]++.
With this the output will be (try it on the Go Playground):
map: map[Push 1:map[Active:2 Checked:1 InActive:1] Push 2:map[Active:1 InActive:1]]

Firebase #Exclude with kotlin data class

I have this data class in Kotlin (example):
import com.google.firebase.database.Exclude
data class User(val name: String = "", #Exclude val age: Int = 0)
And I don't want to save the age property in firebase. #Exclude should do this but it does not work, age is still saved.
Are there any workarounds?
Placing #Exclude on a property targets its generated field and not its generated get accesor method. To do the latter you'll need to prefix "Exclude" with "get:". e.g.:
data class User(val name: String = "", #get:Exclude val age: Int = 0)
See Annotation Use-site Targets for more details.
Actually you don't need to add only #get:Exclude but you need all 3 Exclude,
#Exclude #set:Exclude #get:Exclude.
I did it for imageUrl and providerId
data class FirebaseChatModel(
#get:PropertyName("message")
#set:PropertyName("message")
var message: String = "",
#get:PropertyName("type")
#set:PropertyName("type")
var type: Int = 1,
#get:PropertyName("senderId")
#set:PropertyName("senderId")
var senderId: Int = 0,
#get:PropertyName("receiverId")
#set:PropertyName("receiverId")
var receiverId: Int = 0,
#Exclude #set:Exclude #get:Exclude var imageUrl: String? = "",
#Exclude #set:Exclude #get:Exclude var providerId: Int = 0
)

Resources