What is the difference between ObservableMap and ObservableArray in mobx - reactjs

As per the documentation,
observable.map(values?) creates a dynamic keyed observable map.
Observable maps are very useful if you don't want to react just to the
change of a specific entry, but also to the addition or removal of
entries.
I may be the only one who doesn't understand the difference between these two mobx observable types. Even the doc says map can track addition or removal, following array also notifies the console by autorun when a new value is pushed into the array. So what is the real difference between the two?
window.q = observable([1,2,3]);
autorun(()=>{console.log(q[0]);})
q.push(32)

The difference is in the methods you use to interact with them. Think of one as an array, and the other as a map. Arrays stores indices, maps store keys and values.

Related

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));

Firebase Firestore: Append/Remove items from document array

I am trying to append/remove items from an array inside of a Firestore Document but every time the entire array is replaced instead of the new value being appended. I have tried both of the following:
batch.setData(["favorites": [user.uid]], forDocument: bookRef, options: SetOptions.merge())
batch.updateData(["favorites": [user.uid]], forDocument: bookRef)
I know that instead of an array I can use an object/dictionary but that would mean storing additional data that is irrelevant (such as the key), all I need is the ID's stored inside the array. Is this something that is currently possible in Firestore?
Update elements in an array
If your document contains an array field, you can use arrayUnion() and arrayRemove() to add and remove elements. arrayUnion() adds elements to an array but only elements not already present. arrayRemove() removes all instances of each given element.
let washingtonRef = db.collection("cities").document("DC")
// Atomically add a new region to the "regions" array field.
washingtonRef.updateData([
"regions": FieldValue.arrayUnion(["greater_virginia"])
])
// Atomically remove a region from the "regions" array field.
washingtonRef.updateData([
"regions": FieldValue.arrayRemove(["east_coast"])
])
See documentation here
Actually, nowadays it is possible. With latest updates db.collection.updateData
method actually appends new item to array instead of replacing it.
Example usage can be found in Firebase documentation.
If you need to do it manually, you can use
FieldValue.arrayUnion([user.uid])
Nope. This isn't possible.
Arrays tend to be problematic in an environment like Cloud Firestore where many clients could theoretically append or remove elements from an array at the same time -- if instructions arrive in a slightly different order, you could end up with out-of-bounds errors, corrupted data, or just a really bad time. So you either need to use a dictionary (where you can specify individual keys) or replace the entire array.

What's the difference between #clone and #dup

So I've been learning crystal without a ruby background and noticed the api docs have #dup and #clone for basically copying an array.
What exactly is the difference between the two? The api says #dup shallow copies the array whilst #clone deep copies said array. I'm not sure what exactly that entails and which one I should be using.
#dup will duplicate the array in memory, that is the list of items it contains, but it won't duplicate the items themselves. Mutating the new array won't affect the previous array(e.g. push, pop) but mutating any of its items will affect the item of the previous array since the items are the same objects.
#clone will duplicate the array list in memory, but also its items, by calling #clone recursively. This is a full clone of the original array. Mutating anything, even a deep nested object, won't affect the original content.
Note that this applies to any object, not just arrays, and that the behavior can be customised by overriding the methods in your own objects.
That being said, it only applies for arrays of objects (e.g. class instances). For arrays of primitives (integer, float, struct...) the items will be copied along with the array list by #dup.

Storing array data in firebase, and how ID's are generated

I have a set of objects in my firebase data that all have an array under them. When I create the initial object, I create the initial array with its first object with a line of code like this:
ref.child('items').set([{firstobject: id123}])
this seems to set the id to zero, as the first item in the array. However when I later try to push() a new item to the array with this line of code, I get a more complex id (ZwPiVMIrzbSdvfwxkts).
ref.child('items').push(someNewObject);
In your first line of code, you're calling the Firebase.set() method passing it a JavaScript array that contains a single object.
In your second line of code, you're calling the Firebase.push() method with an object.
Given that Firebase lists/collections are not the same as JavaScript arrays, you end up with a mismatch.
Unlike JavaScript arrays, Firebase's lists are architected to scale well in highly concurrent, multi-user scenarios. I'd recommend to use them instead of arrays from the start.
ref.child('items').push({firstobject: id123});
ref.child('items').push(someNewObject);
With this snippet, all your items will be stored under so-called push ids.

How to initialize a Ref<?> field in objectify to a dummy value

I have a collection(arraylist) of Ref `s ,the objectify documentation says that I need to initialize collections for them to be persisted and hence modified in the future.....
Now , Ref points to an object but when I launch my app for the first time I dont have any objects in the data store...so whats the best way for me to initialize a dummy value......
Is my assumption that a Ref<> needs to point to a real object in the data store?
Two things:
You should just initialize an empty collection. You don't need to add anything to it. eg, field = new ArrayList<Ref<Thing>>();
It's actually not even required that you initialize the collection. It's just a good idea for reasons that will become apparent if you use the system for a while.

Resources