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.
Related
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.
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*/));
});
How can I pass computes into components, such that changing the value in selected in one component will affect a value in a different component.
Example
http://jsbin.com/feleko/1/edit?html,js,console,output
I'm trying to set it up so that selecting a value in the first select changes the options available in the second. I think listening for dom change events should be straightforward, but I don't seem to be getting a compute I can update, or have access to the parent scope in order to use an attribute name to update it. Likewise the max value isn't an active object that receives updates.
I've found an obtrusive way. can.mustache provides a data helper that puts the current context on the element's data.
<select {{data 'context'}} value="a">
Then in the init event I can capture the element data and assign it to the scope so it's available to scope functions.
events: {
init: function(el, opt) {
opt.scope.context = el.data('context')
}
}
Looking up values is then possible if awkward.
this.context[this.attr('value')]
I am trying to convert an existing process in a way that it supports multi-threading and concurrency to make the solution more robust and reliable.
Take the example of an emergency alert system. When a worker clocks-in, a new Recipient object is created with their information and added to the Recipients collection. Conversely, when they clock-out, the object is removed. And in the background, when an alert occurs, the alert engine will iterate through the same list of Recipients (foreach), calling SendAlert(...) on each object.
Here are some of my requirements:
Adding a recipient should not block if an alert is in progress.
Removing a recipient should not block if an alert is in progress.
Adding or removing a recipient should not affect the list of
recipients used by an in-progress alert.
I've been looking at the Task and Parallel classes as well as the BlockingCollection and ConcurrentQueue classes but am not clear what the best approach is.
Is it as simple as using a BlockingCollection? After reading a ton of documentation, I'm still not sure what happens if Add is called while I am enumerating the collection.
UPDATE
A collegue referred me to the following article which describes the ConcurrentBag class and how each operation behaves:
http://www.codethinked.com/net-40-and-system_collections_concurrent_concurrentbag
Based on the author's explanation, it appears that this collection will (almost) serve my purposes. I can do the following:
Create a new collection
var recipients = new ConcurrentBag();
When a worker clocks-in, create a new Recipient and add it to the collection:
recipients.Add(new Recipient());
When an alert occurs, the alert engine can iterate through the collection at that time because GetEnumerator uses a snapshot of the collection items.
foreach (var recipient in recipients)
recipient.SendAlert(...);
When a worker clocks-out, remove the recipient from the collection:
???
The ConcurrentBag does not provide a way to remove a specific item. None of the concurrent classes do as far as I can tell. Am I missing something? Aside from this, ConcurrentBag does everything I need.
ConcurrentBag<T> should definitely be the best performing class out of the bunch for you to use for such a case. Enumeration works exactly as your friend describes and so it should serve well for the scenario you have laid out. However, knowing you have to remove specific items from this set, the only type that's going to work for you is ConcurrentDictionary<K, V>. All the other types only offer a TryTake method which, in the case of ConcurrentBag<T>, is indeterminate or, in the case of ConcurrentQueue<T> or ConcurrentStack<T> ordered only.
For broadcasting you would just do:
ConcurrentDictionary<string, Recipient> myConcurrentDictionary = ...;
...
foreach(Recipient recipient in myConcurrentDictionary.Values)
{
...
}
The enumerator is once again a snapshot of the dictionary in that instant.
I came into work this morning to an e-mail from a friend that gives me the following two answers:
1 - With regards to how the collections in the Concurrent namespace work, most of them are designed to allow additions and subtractions from the collection without blocking and are thread-safe even when in the process of enumerating the collection items.
With a "regular" collection, getting an enumerator (via GetEnumerator) sets a "version" value that is changed by any operation that affects the collection items (such as Add, Remove or Clear). The IEnumerator implementation will compare the version set when it was created against the current version of the collection. If different, an exception is thrown and enumeration ceases.
The Concurrent collections are designed using segments that make it very easy to support multi-threading. But, in the case of enumerating, they actually create a snapshot copy of the collection at the time GetEnumerator is called and the enumerator works against this copy. That allows changes to be made to the collection without adverse affects on the enumerator. Of course this means that the enumeration will know nothing of these changes but it sounds like your use-case allows this.
2 - As far as the specific scenario you are describing, I don't believe that a Concurrent collection is needed. You can wrap a standard collection using a ReaderWriterLock and apply the same logic as the Concurrent collections when you need to enumerate.
Here's what I suggest:
public class RecipientCollection
{
private Collection<Recipient> _recipients = new Collection<Recipient>();
private ReaderWriterLock _lock = new ReaderWriterLock();
public void Add(Recipient r)
{
_lock.AcquireWriterLock(Timeout.Infinite);
try
{
_recipients.Add(r);
}
finally
{
_lock.ReleaseWriterLock();
}
}
public void Remove(Recipient r)
{
_lock.AcquireWriterLock(Timeout.Infinite);
try
{
_recipients.Remove(r);
}
finally
{
_lock.ReleaseWriterLock();
}
}
public IEnumerable<Recipient> ToEnumerable()
{
_lock.AcquireReaderLock(Timeout.Infinite);
try
{
var list = _recipients.ToArray();
return list;
}
finally
{
_lock.ReleaseReaderLock();
}
}
}
The ReaderWriterLock ensures that operations are only blocked if another operation that changes the collection's contents is in progress. As soon as that operation completes, the lock is released and the next operation can proceed.
Your alert engine would use the ToEnumerable() method to obtain a snapshot copy of the collection at that time and enumerate the copy.
Depending on how often an alert is sent and changes are made to the collection, this could be an issue but you might be able to still implement some type of version property that is changed when an item is added or removed and the alert engine can check this property to see if it needs to call ToEnumerable() again to get the latest version. Or encapsulate this by caching the array inside the RecipientCollection class and invalidating the cache when an item is added or removed.
HTH
There is much more to an implementation like this than just the parallel processing aspects, durability probably being paramount among them. Have you considered building this using an existing PubSub technology like say... Azure Topics or NServiceBus?
Your requirements strike me as an good fit for the way standard .NET events are triggered in C#. I don't know offhand if the VB syntax gets compiled to similar code or not. The standard pattern looks something like:
public event EventHandler Triggered;
protected void OnTriggered()
{
//capture the list so that you don't see changes while the
//event is being dispatched.
EventHandler h = Triggered;
if (h != null)
h(this, EventArgs.Empty);
}
Alternatively, you could use an immutable list class to store the recipients. Then when the alert is sent, it will first take the current list and use it as a "snapshot" that cannot be modified by adding and removing while you are sending the alert. For example:
class Alerter
{
private ImmutableList<Recipient> recipients;
public void Add(Recipient recipient)
{
recipients = recipients.Add(recipient);
}
public void Remove(Recipient recipient)
{
recipients = recipients.Remove(recipient);
}
public void SendAlert()
{
//make a local reference to the current list so
//you are not affected by any calls to Add/Remove
var current = recipients;
foreach (var r in current)
{
//send alert to r
}
}
}
You will have to find an implementation of an ImmutableList, but you should be able to find several without too much work. In the SendAlert method as I wrote it, I probably didn't need to make an explicit local to avoid problems as the foreach loop would have done that itself, but I think the copy makes the intention clearer.
Imagine a list with some items.
Each item is a movie and includes:
the title
a ranking with stars (1-5)
add to my list button
a textbox that you might leave a comment
How might be done:
A) The item will listen for the buttonClicked event and then will call a method on the model:
onClick: function(event){
this.model.addToMyList();
}
there is no need to specify the movieId because the "model" is for this item. In the other cases the model is for all the items.
B The list will listen for an item to dispatch the buttonClicked event, gets data from the event and will call a method on a model:
model.addToMyList(movieId)
C The list will listen for an item to dispatch the buttonClicked event, this event will carry on the index(that is not the id of the movie) of the item, then finds the movieId using the index on the list and will call a method on a model:
model.addToMyList(movieId)
You don't mention any languages so I'm going to give a language neutral response.
Don't recommend C: Identifying an item by the index in a list might seem an easy option but any extension functionality or maintainability could get messy later (suddenly ordering a list, having users filter the list etc).
With maintainability in mind (not pre-emptive design but design that'll be more accommodating to changes), it's best for the event handler to be able to identify what's being handled. That way, you could modify the handler that will apply for all items.
With B: I'd more reserve that for a collection that changes, with the intention that controls/components are listening for a collection change (such as INotifyCollectionChangedin .net). So it's a difficult thing to say not knowing whether there's specific actions you want to do with this collection but it wouldn't be my first choice unless the collection (as a data model) change determines other aspects.
So with the above in mind, (this will sound like an A-B hybrid but its a commonly used solution): new items created are signed up to an event handler (just code one event handler), and pass in either the reference to the item-row itself or an identifier. So, if its possible, you'd be looking at:
onClick: function(MyEvent e)
{
this.model.addToMyList(e); //or this.model.addToMyList(e.ID)
}
So you have multiple items signing up for the same event, one event handler to maintain and the ability to preserver that handling should your list be changed through filters, sorting etc.