While transaction can be indeed a more intuitive solution, similar solution can be probably achieved with streamstats. First "split" your times to have it as | eval starttime=if(status=="started",_time,null()) | eval endtime=if(status=="connected",_time,null()) Then you can "collect" your times with | streamstats min(starttime) as timestarted min(endtime) as timeended by userId If you now want to remove the "extra" events with "connected" status, you can do | where NOT (status=="connected" AND _time!=timeended) Bonus - you can use the same approach if there is a possibility of multiple "started" events (we'll leave it as an exercise for the reaer ;-)) Now you're left with just one "started" event and one "connected" event. So we're down to your last requirement - ther must be both "start" event and "connected" event. This can be done in various ways but we can do it along our duration calculation | stats range(_time) as duration values(state) as states by userId And we only want to keep those results which have both states | where states="started" AND states="connected" Now you're all set to group, summarize, bin, and do whatever you want with your results. To be quite honest, I'm not sure what you mean by your C) requirement. Because if it does what I think may mean, the above search is completely not what you want 😄
... View more