Firestore update array field in a Document - firebase

I have a document like below, in my document, have a Array . in array have Objects. How can i update new object to an Array.
As you see below i can add document in a colletion wit an array, but when i tried to update it gives error
java.lang.IllegalArgumentException: Invalid data. Unsupported type: com.test.data.modal.Product
What i tried;
var pid = ""
btnAdd.setOnClickListener {
val list = ArrayList<Product>()
list.add(Product("u1", "1", 1))
list.add(Product("u2", "2", 1))
list.add(Product("u3", "3", 1))
val testObject = TestObject("Talha", "Kosen", list)
FirebaseFirestore.getInstance().collection("Test")
.add(testObject)
.addOnCompleteListener { task ->
pid = task.result.id
}
}
btnUpdate.setOnClickListener {
val list = ArrayList<Product>()
list.add(Product("u1", "1", 1))
list.add(Product("u2", "2", 1))
list.add(Product("u3", "3", 1))
list.add(Product("u4", "4", 4))
FirebaseFirestore.getInstance()
.collection("Test")
.document(pid)
.update("product", list)
}
document:
POJO:
#IgnoreExtraProperties
#Keep
class TestObject {
var name: String = ""
var surname: String = ""
lateinit var productList: List<Product>
constructor()
constructor(name: String, surname: String, productList: List<Product>) {
this.name = name
this.surname = surname
this.productList = productList
}
}
#IgnoreExtraProperties
#Keep
class Product {
var imagePath: String = ""
var productUrl: String = ""
var brand: Int = 0
constructor()
constructor(imagePath: String, productUrl: String, brand: Int) {
this.imagePath = imagePath
this.productUrl = productUrl
this.brand = brand
}
}

I have probably not the answer but this could help :
You try to update with an ArrayList but you store a List (in your TestObject)
Refer to the documentation to update fields in nested objects https://firebase.google.com/docs/firestore/manage-data/add-data#update_fields_in_nested_objects
It could be a good idea to store a collection in your TestObject document instead of a list ? You'll able to update easily your fields

Related

retrofit 2 post - getting internal server error (500)

I'm trying to use retrofit2 with Koltin in Android Studio as part of jetpack compose application. I'm sending a POST and keep getting error 500. I don't have access to the server code so I'm trying to figure out what am I doing wrong.
This is the interface I have declared for building the retrofit object:
I tried three different ways of declaring the POST endpoint.
#Singleton
interface IsrPayService {
#Headers ("Content-Type: application/json")
#POST("v3/driver/new-credit-driver")
suspend fun signUp(#Body user: UserDriver): Call\<WsError?\>
#Headers (
"Content-Type: application/json",
"Accept: application/json")
#POST("v3/driver/new-credit-driver")
suspend fun signup2(#Body user: UserDriver): retrofit2.Response<WsError>
#FormUrlEncoded
#POST("v3/driver/new-credit-driver")
suspend fun signupUrlEncoded(
#Field("firstName") firstName: String,
#Field("lastName") lastName: String): retrofit2.Response<WsError>
}
The data I am trying to send is UserDriver and I declared all the internal data classes below:
data class UserDriver(
#SerializedName("firstName") val firstName: String = "default",
#SerializedName("lastName") val lastName: String = "default",
#SerializedName("civilId") val civilId: String = "default",
#SerializedName("vehicleLicensingNumber") val vehicleLicensingNumber: String = "default",
#SerializedName("vehicleManufacturer") val vehicleManufacturer: String = "default",
#SerializedName("vehicleModel") val vehicleModel: String = "default",
#SerializedName("vehicleManufactureYear") val vehicleManufactureYear: String = "1973",
#SerializedName("counterModel") val counterModel: String = "default",
#SerializedName("authorizedEmployerNumber") val authorizedEmployerNumber: String = "default",
#SerializedName("bankAccountId") val bankAccountId: String = "default",
#SerializedName("bankAccountBranch") val bankAccountBranch: Int = 0,
#SerializedName("bankId") val bankId:Int = 123456,
#SerializedName("email") val email: String = "default",
#SerializedName("dob") val dob: DateIndicator = DateIndicator(date = 3, month = 4, year = 2023),
#SerializedName("address") val address: Address = Address (Coordinates(0,0),"מודיעין","טשרניחובסקי","12"),
#SerializedName("phoneNumber") val phoneNumber: String = "default",
#SerializedName("driverLicenseId") val driverLicenseId: Int = 0,
#SerializedName("civilIdPhoto") val civilIdPhoto: String = "default",
#SerializedName("driverLicensePhoto") val driverLicensePhoto: String = "default",
#SerializedName("signaturePhoto") val signaturePhoto: String = "default"
)
data class DateIndicator(
#SerializedName("date")
#Expose
val date: Int,
#SerializedName("month")
#Expose
val month: Int,
#SerializedName("year")
#Expose
val year: Int
)
I think #Expose is not required but tried it just in case..
data class Address (
#SerializedName("coordinates")
#Expose
val coordinates: Coordinates,
#SerializedName("city")
#Expose
val city: String,
#SerializedName("street")
#Expose
val street: String,
#SerializedName("number")
#Expose
val number: String
)
data class Coordinates (
#SerializedName("latitude")
#Expose
val latitude: Int,
#SerializedName("longitude")
#Expose
val longitude: Int
)
I tried to methods of getting the response:
suspend fun driverSignUp(user: UserDriver, onResult: (WsError?) -> Unit) {
try {
ws.signUp(user = user). enqueue (
object: Callback<WsError?> {
override fun onResponse(call: Call<WsError?>, response: Response<WsError?>) {
Log.d("driverSignUp",
"onResponse: response.isSuccessful = ${response.isSuccessful}")
var wsError: WsError? = null
wsError = if(!response.isSuccessful){
WsError(
body = "",
isError = true,
error = yz.learning.isrpaytest.model.Error(
errorCode = response.code(),
errorMessage = ErrorMessage(
enUs = response.message(),
heIl = response.message())))
} else {
response.body()
}
onResult(wsError)
}
override fun onFailure(call: Call<WsError?>, t: Throwable) {
Log.d("driverSignUp", "onFailure: ")
onResult(null)
}
}
)
} catch (exception: Exception) {
Log.d("driverSignUp", "driverSignUp exception: ${exception.message}")
onResult(
WsError(
body = "",
isError = true,
error = yz.learning.isrpaytest.model.Error(
errorCode = 0,
errorMessage = ErrorMessage(
enUs = exception.message!!,
heIl = exception.message!!)))
)
}
}
suspend fun driverSignUp2(user: UserDriver): retrofit2.Response<WsError>{
return ws.signup2(user)
}
I don't understand why I keep getting Internal server error. I have a feeling I have to send the data as a JSON string and not as an Object but as far as I understand this is supposed to be automatically using the gson converter, no?
I can try a simpler endpoint, but I think I will end up with the same problem.
I will appreciate any help since I'm stuck with this issue for a couple of days.
Thanks,
Yariv

I found error in kotlin java.lang.IllegalArgumentException: Invalid data. Unsupported type: com.scrollupstudio.projemanag.models.Task

I found an error in kotlin when I update data on Cloud Firestore:
java.lang.IllegalArgumentException: Invalid data. Unsupported type: com.scrollupstudio.projemanag.models.Task
at com.scrollupstudio.projemanag.firebase.FirestoreClass.addUpdateTaskList(FirestoreClass.kt:155)
at com.scrollupstudio.projemanag.activities.TaskListActivity.createTaskList(TaskListActivity.kt:63)
at com.scrollupstudio.projemanag.adapters.TaskListItemAdapter$onBindViewHolder$3.onClick(TaskListItemAdapter.kt:63)
This is the code error on update(taskListHashMap)
fun addUpdateTaskList(activity: TaskListActivity, board: Board){
val taskListHashMap = HashMap<String, Any>()
taskListHashMap[Constants.TASK_LIST] = board.taskList
Log.d("FirestoreClass", "id : ${board.documentId} dengan ini : ${taskListHashMap.toString()}")
mFirestore.collection(Constants.BOARDS)
.document(board.documentId)
.update(taskListHashMap)
.addOnSuccessListener {
Log.e(activity.javaClass.simpleName, "TaskList update successfully")
activity.addUpdateTaskListSuccess()
}
.addOnFailureListener {
exception ->
activity.hidePorgressDialog()
Log.e(activity.javaClass.simpleName, "Error", exception)
}
}
This is my Board model:
#Parcelize
data class Board(
val name: String = "",
val image: String = "",
val crearedBy: String = "",
val assignedTo: ArrayList<String> = ArrayList(),
var documentId: String = "",
var taskList: ArrayList<Task> = ArrayList()
): Parcelable
This is my Task model:
#Parcelize
data class Task(
var title: String = "",
val createdBy: String = ""
): Parcelable
/sc

Amazon DynamoDBv2 QueryOperationConfig SelectValues.Count not working

I have this piece of code like this:
var options = new DynamoDBOperationConfig
{
ConditionalOperator = ConditionalOperatorValues.Or,
OverrideTableName = nameTable,
ConsistentRead = true
};
new QueryOperationConfig()
{
IndexName = indexName,
Filter = queryFilter,
Select = SelectValues.Count
};
result = context.FromQueryAsync<TEntity>(queryConfig, options).GetRemainingAsync().Result;
as per the documentation, it should return just the count of values that match the filter, at least, the piece of code in the SelectValues class says that
//
// Summary:
// An enumeration of all supported Select values for Query and Scan. Value of Count
// will force service to return the number of items, not the items themselves.
but result is always an empty list; how can i make the count work ?
If you are still looking for the answer, this is the solution:
new QueryOperationConfig()
{
IndexName = indexName,
Filter = queryFilter,
Select = SelectValues.Count,
ConsistentRead = true
};
var table = context.GetTargetTable<TEntity>();
var search = table.Query(queryConfig);
result = search.Count;
Having ConsistentRead set to true will cause it to give you real time updates when the table is updated.
It's not working on Document level...
You can try to do this in low level model.
int count = 0;
Dictionary<string, AttributeValue> lastKey = null;
do
{
var request = new QueryRequest
{
TableName = "tableNmae",
IndexName = "indexName",
KeyConditionExpression = "ID= :v_ID",
ExpressionAttributeValues = new Dictionary<string, AttributeValue>
{
{
":v_ID",
new AttributeValue
{
N = "1"
}
}
},
ConsistentRead = false,
Select = Select.COUNT,
ExclusiveStartKey = lastKey
};
var respone = await tableClient.QueryAsync(request);
count += respone.Count;
lastKey = respone.LastEvaluatedKey;
} while (lastKey != null && lastKey.Count != 0);

VaultCustomQueryCriteria for State in Corda

I am trying to query a state from vault without using the linear Id of the state and instead an Int(unique) variable present in Schema
val sNumber = AState.ASchemaV1.AEntity::SNumber
val QueryCriteria = QueryCriteria.VaultCustomQueryCriteria(sNumber.equal(SalesNumber))
val StateAndRef = serviceHub.vaultService.queryBy<AState>(QueryCriteria).states.single()
val outState = StateAndRef.state.data
The Query criteria is not throwing any error but I am also not getting any output but on debugging I got an error response
javax.persistence.PersistenceException: org.hibernate.InstantiationException: No default constructor for entity: AState.ASchemaV1.AEntity
but I have defined all the columns in the function. What am I missing?
Here is code for Schema
override fun supportedSchemas() = listOf(ASchemaV1)
override fun generateMappedObject(schema: MappedSchema) = ASchemaV1.AEntity(this)
object ASchemaV1 : MappedSchema(AState::class.java, 1, listOf(AEntity::class.java)) {
#Entity
#Table(name = "Table")
class AEntity(A: AState) : PersistentState() {
#Column
var CONumber: String = A.linearId.id.toString()
#Column
var SalesNumber: Int = A.SalesNumber
#Column
var ProductID: Int = A.ProductID
#Column
var Quantity: Int = A.Quantity
#Column
var Rate: Double = A.Rate
#Column
var DeliveryDate: Date = A.DeliveryDate
#Column
var DeliveryLocation: String = A.DeliveryLocation
#Column
var Status: String = A.Status.toString()
}
}
AState.ASchemaV1 is missing the constructor.
object ASchemaV1 : MappedSchema(AState::class.java, 1, listOf(AEntity::class.java)) {
#Entity
#Table(name = "Table")
class AEntity(
#Column
var CONumber: String,
#Column
var SalesNumber: Int,
#Column
var ProductID: Int,
#Column
var Quantity: Int,
#Column
var Rate: Double,
#Column
var DeliveryDate: Date,
#Column
var DeliveryLocation: String,
#Column
var Status: String
): PersistentState() {
constructor(A: AState): this(A.linearId.id.toString(), A.SalesNumber, A.ProductID, A.Quantity, A.Rate, A.DeliveryDate, A.DeliveryLocation, A.Status.toString())
}
}

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