select only the most recent value from a Store - rxjs

some searching on SO leaves me to believe that there is no good (simple) way of achieving the question in the title. The following threads are all very related:
Get current state in ngrx
Getting current state in ngrx
Get current ngrx state without subscribe
Using ngrx to obtain store's current state once
How to get current value of State object with #ngrx/store?
From the last thread ^, it seems that the only way of achieving this is to use withLatestFrom() or combineLatest().
It can't be the case that the following is the only way to make sure you only receive 1 item and that this item is the most recent one:
of('terribleLatestValueHack').pipe(
withLatestFrom(this.store.select(itemSelector))
).subscribe((stringAndItem: [string, Item]) => {
const [, item] = stringAndItem;
// do something with item
});
Given that selecting one most recent item from a Store
is a (very) simple use-case
seems to be a highly requested functionality
I would really like to know why the existing support (apparently there was - in NGRX v2 - according to How to get current value of State object with #ngrx/store?) for it has been removed.

I forgot to add that I was of the impression that store.select(...).pipe(first()) does not return the most recent item from the store. But it seems it does and the cause for any faulty values it returns lies in our own code.
store.select(...).pipe(first()) indeed just does that: return one current item from a Store (and complete the Observable).

Related

How to get an event ID from the HitID returned by a Microsoft Graph search query?

I am trying to patch a calendar event with the Microsoft Graph API (from a Node express app).
I create a new event with client.api('/me/events').post(myEvent) and it works just fine (I see it appear in my calendar). The return value has an ID which is:
AAMkADc0Yjg2ODdmLTlkNDQtNGQ0Yi1iNjBmLTE1MDdmYzI4MGJkOABGAAAAAADt0ZJy6xMCRq23C8icFGeqBwAOM3XMH4d2SYMQ5psbvFytAAAAAAENAAAOM3XMH4d2SYMQ5psbvFytAAJ_B-B7AAA=
I then use client.api('/search/query').post(myQuery) to find the event based on some criteria, and this works fine. I receive an array of hits, with only one hit (which actually is the freshly created event, looking at the subject and body), and with a hitId equal to:
AAMkADc0Yjg2ODdmLTlkNDQtNGQ0Yi1iNjBmLTE1MDdmYzI4MGJkOABGAAAAAADt0ZJy6xMCRq23C8icFGeqBwAOM3XMH4d2SYMQ5psbvFytAAAAAAENAAAOM3XMH4d2SYMQ5psbvFytAAJ+B/B7AAA=
For some reason I don't understand why the 2 IDs are not fully identical: the _ is changed to +and -changed to /.
I now want to modify the event, and try to update it with
let newVal = hits[0].resource // hits is coming from the result returned by the search query
newVal.id = hits[0].hitId // needed because the 'resource' does not contain the id
client.api('/me/events/'+hitId).patch(newVal)
But I get an error: Resource not found for the segment 'B7AAA='.
Could you please tell me how to make the patch work (and explain why the ID from the search is not strictly like the one created). I have read several examples in the documentation (such as https://learn.microsoft.com/en-us/graph/search-concept-events) but I could not find a solution.
Many thanks!
So what is happening here is, PATCH /me/events/{hitId} is being resolved by Graph API such that the forward slash in the hitId denotes a path and Graph ends up using B7AAA= as a resource id hence the error Resource not found for the segment 'B7AAA='.
A work around that might work is to replace / in hitId(s) with %252F. You can do it like this.
client.api(`/me/events/${hitId.replace('/', '%252F')}`).patch(patch)
There is already this Issue on GitHub for documentation on how to handled these base64 encoded resource ids with /
As for the two IDs being non identical, Graph API will accept both of them and resolve to the same resource. I have no idea why they are different though.

Mixpanel: Undo or delete an event

On MixPanel, I track an event like so:
mixpanel.track('Action A')
I allow visitors to undo their actions when filling out a sign-up form. I would like to be able to send another event to undo the previous event:
mixpanel.decrement('Action A')
However, the decrement function in Mixpanel is only available on user properties, not events. I don't have unique_ids on these events because it's server-side and triggered by anonymous users, but I would like the ability to increment and decrement an accurate count of Action A. How can I delete the initial event or decrement the count by 1?
There is no way to delete events that are ingested by Mixpanel with no unique_id's connected to them.
It is possible to hide them so they don't appear in reports, but that sounds like it will defeat the purpose of what you are trying to accomplish.
Mixpanel does have documentation on making an incremental super property, which is tied to events and not people. A super property is a property that is sent with every event. The method mixpanel.register() is what is used to create Super Properties, but it also allows values to be overwritten which is one way to build an incremental/decremental event property.
This unfortunately involves building a function, but it should serve as a workaround. If you are using JS the function would look something like:
//define the incrementing function
incrementer = function(property) {
value = mixpanel.get_property(property);
update = {}
//Ensure that 'value' has a type = number
if(value && typeof(value) == 'number') {
update[property] = value +1;
}
else {
update[property] = 1
}
mixpanel.register(update);
};
There is some documentation on this here.
I think this will involve a little bit of tweaking depending on your implementation, but let me know if that helps solve it.

How to correctly subscribe to Changed sequence of ReactiveObject?

Another question about ReactiveUi. I have a ViewModel for an edit form. Model is ReactiveObject. I want to enable savecommand only when changes of object was take place. My try:
var canSaveCommand =
this.WhenAnyValue(vm => vm.CurrentClient)
.Where(client => client != null)
.Select(client =>
client.Changed
)
.Any();
But when the form appears the SaveCommand is already enabled. Where my mistake?
You want to use Switch not SelectMany. SelectMany will not unsubscribe from the previous client. It will merge events from all clients. Switch unsubscribes from the previous client before it subscribes to the next.
var canSaveCommand =
this.WhenAnyValue(vm => vm.CurrentClient)
.Where(client => client != null)
.Select(client =>
client.Changed
)
.Switch()
.Any();
For example the following code makes it clear. Let's say we have a class called AudioChannel It generates audio frames we can can process and send to the speaker.
public class IAudioChannel {
public IObservable<AudioFrame> AudioFrameObservable {get;}
}
Then we might have a list of audio nodes that the user can select but we only want the most current sending audio to the speaker. The below class makes available the currently selected audio node as an observable.
public class AudioListViewModel {
public class IObservable<IAudioChannel> CurrentAudioChannelObservable {get;}
}
Now consider the following code
AudioListViewModel viewModel;
viewModel
.CurrentAudioChannelObservable
.SelectMany(current=>current.AudioFrameObservable)
.Subscribe(frame=>frame.Play());
vs
AudioListViewModel viewModel;
viewModel
.CurrentAudioChannelObservable
.Select(current=>current.AudioFrameObservable)
.Switch()
.Subscribe(frame=>frame.Play());
In the first version as we change the selection of audio nodes we add more and more subscriptions. The audio output quickly becomes a garbled mess of mixed channels. In the second version only one channel is subscribed to at a time and the audio output only plays the output from a single channel.
Many people make this mistake when starting out with RX. For example I found a bug in the ReactiveUI framework that used SelectMany instead of Switch.
However
There is a built in way within ReactiveUI to achieve this in a clear way
There is actually another way to achieve what you want and I will put it in another answer just to show you how to use ReactiveUI.
var canSaveCommand =
this
.WhenAnyObservable(vm => vm.CurrentClient.Changed)
.StartWith(false);
Note that null doesn't have to be explicity handled though you should start with false to make sure a value exists when no observable is available to start with.
WhenAnyObservable
WhenAnyObservable acts a lot like the Rx operator CombineLatest, in
that it watches one or multiple observables and allows you to define a
projection based on the latest value from each. WhenAnyObservable
differs from CombineLatest in that its parameters are expressions,
rather than direct references to the target observables. The impact of
this difference is that the watch set up by WhenAnyObservable is not
tied to the specific observable instances present at the time of
subscription. That is, the observable pointed to by the expression can
be replaced later, and the results of the new observable will still be
captured. An example of where this can come in handy is when a view
wants to observe an observable on a viewmodel, but the viewmodel can
be replaced during the view's lifetime. Rather than needing to
resubscribe to the target observable after every change of viewmodel,
you can use WhenAnyObservable to specify the 'path' to watch. This
allows you to use a single subscription in the view, regardless of the
life of the target viewmodel.
Try changing your Select to a SelectMany. That will then give you an Observable of the changes to be passed into Any instead of an Observable of an Observable of the changes to be passed into Any.

Split node.js event stream based on unique id in event body

I have a node.js-based location service that produces events as users move about, and I want to use RxJS to process these events and look for arbitrarily complex patterns like a user enters a region and visits 2 points of interest within 1 hour.
To begin with I need to split the stream of events base on unique user ids (from event body), but I am not finding any stock RxJS functions that will do this.
filter() would require that all uuids be known beforehand which is not desirable.
groupBy() looks like it would need to process the entire sequence prior to returning the grouped observables, which is not possible.
I'm thinking that maybe I need to build a custom observable that maintains a map of uuids to observables, and instantiate new observables as required. Each of these observables would then need to undergo identical processing in search of the pattern match, and ultimately trigger some action when a user's movements match the pattern. One of the obvious challenges here is I have a dynamically growing map of observables being produced as user enter the system and move about.
Any ideas how something like this could be achieved with RxJS?
I think you are misunderstanding how groupBy() works. It will generate a new Observable every time a new key is generated, and if the key already exists, it will just be pushed to the existing Observable.
So for your problem it should look something like this:
var source = getLocationEvents();
var disposable = new Rx.CompositeDisposable();
disposable.add(
source.groupBy(function(x) { return x.userid; })
.map(function(x) {
return x.map(function(ev) { /*Process the the event*/ });
})
.subscribe(function(group) {
disposable.add(group.subscribe(/*Do something with the event*/));
});

request.object.previous() is not working in beforeSave()

I'm trying to check the current and previous value of an attribute in the beforeSave(). So i tried to use request.object.previous("attribute_name") but it is still returning the current changed value. Although the .ditry() is returning TRUE which means that the value is changed. Any idea what is wrong here ? I appreciate your feedback.
I think the .previous() isn't actually part of the Parse.com sdk, but simply inherited from backbone.
In a beforeSave handler, I have something like:
if(object.dirty("attr")) {
console.log("After: " + object.get("attr") + ", Before: " + object.previous("attr")); }
The value returned by 'previous' is always the same. Is this functionality actually
implemented? I've seen a few threads elsewhere that imply it's not -
if so, can you remove it from the API docs until it's done?
If it doesn't work, is the correct workaround to query the previous
object? Or does 'changedAttributes' work?
Oh, I now see that 'previous' is some cruft from Backbone.
source1
previous is a method inherited from Backbone.Model. It won't return the previous value of a field in Cloud Code.
source2
Might not be the answer you're looking for, so as a way to workaround the lack of the .previous implementation this this out:
Don't know if this is helpful or if it would be considered too costly
of a workaround, but you could add a column to the object that is
being updated that stores the previous value of the original column.
This would allow you to access the previous value in the AfterSave
function.

Resources