How to loop through and edit a JsonArray of objects in Scala - arrays

I have a variable descriptions that is an Option[JsonArray] (JsonArray results from calling getJsonArray on a JsonObject). descriptions is a list of objects that I'm getting back as a response from a server. Each object has a structure like so:
{age: String,
number: Long,
link: String}
I'd like to loop through this JsonArray and edit the link field to a certain value that is returned from a function. I don't even need to edit it in place and can take a new array of objects. In JS, it might be as simple as descriptions.map(d => ({...d, link: someValue})) but I'm not sure how I need to transform the JsonArray to get this working in Scala. Any help is appreciated!

#mysl didn't provide necessary details as mentioned in the comments. So I'm going to speculate that the approach you've proposed didn't work and you want to understand why.
Most probably you've assumed that JsonArray would be mutated when you .map a lambda over it (which is the case for Javascript I guess). That's not true in Scala case. I.e. when you map a list over you've got another list. I.e. .map, as the name assumes, is just a way to map one collection to another.
So what you need to do is:
val originalJsonArray = ...
val updatedJsonArray = originalJsonArray.map { description =>
description.copy(link = description.link.replace("foo","bar"))
}
println(s"originalJsonArray=$originalJsonArray, updatedJsonArray=$updatedJsonArray")
I hope that helps, though I'm not sure I guessed your problem correctly.

Related

How to map array of objects

I have some problems mapping an array of objects in JS.
This is how the response looks in my console:
[{...}]
...and when I expand it I get this:
0:{id:0, document:{...}}
1:{id:1, document:{...}}
Usually the response I get is always without this number in front of each object, like this:
{id:0, document:{...}
{id:1, document:{...}
I tried every approach I know and I cant't manage to handle it.
The goal is to take each value out of "document" property and dynamically display it in some kind of table.
This is the way the browser devtools decides to display the array, but it is actually correct, if I'm not mistaken you're still dealing with an array.
You can verify this by logging the following:
(Replace myVar with the variable name you chose for your response array)
console.log(Array.isArray(myVar))
If it outputs true then you're fine and you are dealing with an array.

The api returns both an object and an array

I'm new to json, there was a problem and I couldn't find a solution
I was given an api and when executing a get request, I get some object, but if there is no data in the object, an array is returned.
At the moment I was able to get Any?, instead of JSONArray or JSONObject, but there was a problem with converting Any? to the class
How to convert data to kotlin data class correctly?
returned object
returned array
The class I'm converting the json request to:
data class ProductInfo (var product:Product?,var specifications: JsonObject?,var supplements: Any?,var files:List<File>?,var feedback: Feedback?)
This seems something that the backend has to solve for you. They can give you a nullable array or just an empty array, whatever is more convenient, but implementing polymorphism is not something trivial.
Jackson makes polymorphism easier than Gson, however, it is always required some kind of anchor to know how to route the parsing, in this case, you don't have any.
Jackson uses an annotation and there you have indicate in which thing is going to pivot:
#JsonSubTypes.Type(value = Nothing.class, name = "????")
With Gson you have to implement your own JsonDeserializer but again, how do you know what type is it? If it can be cast to array then is nothing? Just writing that seems like an antipattern.

FireStore and maps/arrays, document-list to array in Kotlin

I've finally started to understand a lot of info regarding FireStore, but I'm wondering if I can get some assistance.
If I had a setup similar to or like this:
          races
                Android
                      name: Android
                      size: medium
                       stats          <---- this is the map
                                str: 10
                                sex: 12.... (more values)
How would I parse this? I am looking to make specific TextViews apply values found in the database so that I can simply update the database and my app will populate those values so that hard coding and code updating won't be nearly as troublesome in the future.
I currently use something like this:
val androidRef = db.collection("races").document("Android")
androidRef.get().addOnSuccessListener { document ->
if (document != null) {
oneOfTheTextViews.text = document.getString("str")
} else {
}
The issue is currently I can only seem to access from collection (races) / document (android) / then a single field (I have "str" set as a single field, not part of a map or array)
What would the best practice be to do this? Should I not nest them at all? And if I can reference said nesting/mapping/array, what functions need to be called? (To be clear, I am not asking only whether or not it is possible - the reference guides and documents allude to such - but what property/class/method/etc needs to be called in order to access only one of those values or point to one of those values?).
Second question: Is there a way to get a list of document names? If I have several races, and simply want to make a spinner or recycler view based on document names as part of a collection, can I read that to the app?
What would the best practice be to do this?
If you want to get the value of your str property which is nested within your stats map, please change the following line of code:
oneOfTheTextViews.text = document.getString("str")
to
oneOfTheTextViews.text = document.getString("stats.str")
If your str property is a number and not a String, then instead of the above line of code please use this one:
oneOfTheTextViews.text = document.getLong("stats.str")
Should I not nest them at all?
No, you can nest as many properties as you want within a Map.
Is there a way to get a list of document names?
Yes, simply iterate the collection and get the document ids using getId() function.

How do deal with nested Arrays/objects in BehaviorSubjects, Observables?

I generally have problems using rxjs with nested Objects or Arrays.
My current use-case is this:
{a: [
{b: 0, c:[{d:1}]},
{b: 1, e:[{f: 'someString'}]}
]
Task: Get and set the Observable or value of a,b,c,d,e,f. I also want to be able to subscribe to each property.
I had this Problem in a similar use-case with an Array of BehaviorSubjects:
Efficiently get Observable of an array BehaviorSubjects
I generally have problems to use the basic functionality of nested arrays/objects in rxjs.
The basic functionality I mean includes:
Array:
getting Element by Index
using for of/in on Arrays
setting an Element by Index
push, pop, shift, slice, splice, ...
Object:
getting Value by Property name
going into the nested tree: object.key1.key2.key3[3].key4 ...
setting Value by Property name
assign
for of/in loops
Generally:
Destructuring: e.g.: let [variable1, variable2] = someObject;
Maybe other stuff I forgot.
I dont know if and which functions are possible for which rxjs Objects and which make sense (for example you should be able to set values in an Observable directly). But coming from a background without rxjs, I have trouble to manage my rxjs Objects properly.
I think reason for this besides my lack of knowledge and understanding is, that
a. The rxjs Objects don't provide the functionality as I'm used to from normal arrays and objects. e.g.:
let variable1 = array[1].property;
//becomes this (see related stack-Question I mentioned earlier)
let variable2 = array.pipe(mergeMap(d=> d[index].pipe(map(d1 => d1[property]));
// -> what happens here? You first need to know what mergeMap,
// map is doing and you have 5 levels of nested inline functions.
b. To implement the those mentioned functionalities I need to go over the .pipe() function and use some function like mergeMap, map, pluck, ... Functions that aren't directly indicating that you can get the Observable of let's say 'e' in my example. Making something like object.a[1].e wierd to implement (at least I don't know how to do that yet)
EDIT:
I also want to note, that I still love the idea of rxjs which works well in angular. I just have problems using it to it's full extend, as I'm a bit new to angular and consequently rxjs.
I thin RX is mainly focus on dealing with async operations. Mutation of array and object we can perfectly use the methods comes natively with javascript if theres no existing operators. or you can create your own operator for mutation/iteration etc.
Will try to answer some of your question on array/objects mutation, they are actually very straight forward.
Array:
getting Element by Index
map(arr=>arr[index])
using for of/in on Arrays
map(arr=>arry.map(item=>....))
setting an Element by Index
tap(arr=>arr[index]=somevalue)
Object:
getting Value by Property name
pluck('name')
going into the nested tree: object.key1.key2.key3[3].key4 ...
pluck('key1','key2')
setting Value by Property name
map(obj=>({a:value,obj...}))
assign
lets say your really want some pick array index method as rxjs operator you can create something like, same as for..in operations.
const pluckIndex=(index)=>source=>source.pipe(map(arr=>arr[index]))
const source = of([2,3])
source.pipe(pluckIndex(1)).subscribe(x => console.log(x));

What is the difference between a model object queried by filter and an object queried by get() in Django?

I keep coming across this issue where I am trying to update a record using the update() method.
It always works when I query an object using filter.
my_dictionary = {"key":"Val","another":"Val"}
thing = Thing.objects.filter(pk=1)
thing[0].update(**my_dictionary) wrote it wrong in the original question.
thing.update(**my_dictionary)
When I query the object using get() it keeps telling me that the object has no method update()
my_dictionary = {"key":"Val","another":"Val"}
thing = Thing.objects.get(pk=1)
thing.update(**my_dictionary)
Isn't a model object the same in both cases? Why would one have an update method and the other one not? Any insight would be greatly appreciated.
The documentation is very explicit about this:
filter() will always give you a QuerySet, even if only a single object matches the query - in this case, it will be a QuerySet containing a single element.
If you know there is only one object that matches your query, you can use the get() method on a Manager which returns the object directly.
Your first snippet returns a QuerySet, which has an update method. The second snippet returns a model instance, which doesn't.
Note that you have not shown the exact code you are using: thing[0].update would give exactly the same error as the second snippet.
You're using QuerySet.update() and ModelInstance.save().
If you’re just updating a record and don’t need to do anything with the model object, the most efficient approach is to call update(), rather than loading the model object into memory. For example, instead of doing this:
e = Entry.objects.get(id=10)
e.comments_on = False
e.save()
...do this:
Entry.objects.filter(id=10).update(comments_on=False)

Resources