Mixpanel JQL filter two events with AND condition - mixpanel

I have an query - Let's say If I want to see "Deal Viewed" AND then "Deal Claimed" how can I achieve this.I included these two events in event_selectors,I can see peoples who viewed the deal OR claimed deal. But I want AND instead of OR.
Below is my jql
function main() {
return join(
Events({
from_date: '2017-08-24',
to_date: '2017-08-24',
event_selectors:[{event:"Offer Viewed", selector: 'properties["Offer
Type"]=="Deal"' && 'properties["Offer
Title"]=="testDealtestDealtestDeal"'},
{event:"Offer Claimed"}]
}),
People(),
{ type:"inner"}
);
}

I think you cannot do this directly. What you can do is find profile IDs that match your AND condition, i.e. profiles that have sent both events. You can do so using grouping on Events like this:
function main() {
return Events({
from_date: '2017-11-23',
to_date: '2017-11-24',
event_selectors: [
{ event: "Offer Viewed", selector: 'properties["Offer
Type"] == "Deal"'},
{ event: "Offer Claimed"}
]
})
// Find unique event-name/ID pairs. There will be 1-2 rows for each ID.
.groupBy(["name", "properties.$id"], mixpanel.reducer.any())
.map(e => { return {"event" : e.key[0], "id" : e.key[1]} })
// Find IDs for profiles that sent both events
// (i.e. that are returning 2 items after grouping on ID)
.groupBy(["id"], mixpanel.reducer.count())
.filter(e => { return e.value === 2})
.map(e => { return {"id" : e.key[0]} })
}
But when you try to join it with People(), you'll are bound to get stuck with this restriction of JQL:
Error validating script: Uncaught exception Error: join(Events(), People()) is the only form of join JQL supports.
return join(
One way around this is to set some profile property as well whenever you send events. What we use a lot is a pattern where, let's say when you send Offer Viewed, you also do a profile update and set profile property Offer Viewed At=$timestamp. That way you could skip working with Events here, and just do the filtering on profile properties.
Your other option is to use the query above, and try to get the rest of what you need done on the level of Events.

Related

How to query relational data in ascending order in strapi?

I have this query that works
async find(ctx) {
let { _start, _limit } = ctx.request.query;
console.log(ctx.request.query)
_limit ? 0 : (_limit = 10);
const entities = await strapi.services["course-series"].find({});
return entities.map((entity) => {
// Do I sort them here or in the url query (and how)
entity.courses = entity.courses.slice(_start, _limit);
return sanitizeEntity(entity, { model: strapi.models["course-series"] });
});
}
The idea is that I can load 10 courses from each series at first and then get the next 10...
I just realized that the first 10 I am getting are not the recent ones.
As I commented // Do I sort them here or in the url query (and how)
What version of Strapi do you use?
What does this line do strapi.services["course-series"].find({})? How did you build this find method in the service? What does it do? Does it accept params?
Personally I'd do something like that (assuming you're working with Strapi version > 4:
const entities = await strapi.entityService.findMany('api::course-series.course-series', {
fields: [/* list the course-series fields you want to populate */],
populate: {
courses: {
fields: [/* list the course fields you want to populate */],
sort: 'createdAt:desc', // You can use id, publishedAt or updatedAt here, depends on your sorting prefrences
offset: _start,
limit: _limit // I must admit I haven't tested `offset` and `limit` on the populated related field
}
}
})
// ...the rest of your code, if needed
Read more about Entity Service API here.
Doing it the way you did it, you will always first retrieve the full list of courses for each course-series, and then run costly operations like mapping (the lesser of 2 evils) and above all sorting.

subscribing to nested observables

I'm creating an observable that needs to perform a few steps, each step is reliant on the previous - for example something like get an ID, use that ID to get a user, use that user to get an article. Each step makes a call to the database, which in turn returns its own observable. I'm really not sure how to deal with nested observables without subscribing to them, or ensure that when the outer observable is subscribed to eventually all the nested observables are subscribed to as well.
Example:
newArticle(article: Article): Observable<any> {
// db api returns an observable of requests
return this.db.get(`select id from user_ids where name = ${article.name}`).pipe(map((id) => {
return this.db.get(`select user from users where user_id = ${id}`).pipe(map((user) => {
return this.db.put(`insert into articles(user_name, title, content) values (${user.name}, ${article.title}, ${article.content});
}));
}));
}
Using this current method doesn't work, when the observable returned from newArticle is subscribed to only the outermost observable is subscribed and executed it seems. Is there something I'm missing in the way to deal with nested observables? I'm relatively new to rxjs and having a hard time completely grasping observables. Any help would be greatly appreciated.
In RxJS, the solution to avoid nested subscriptions is to use a "Higher Order Mapping Operator" (switchMap, mergeMap, concatMap, exhaustMap). These operators will subscribe to an "inner observable" for you and emit its emissions.
I won't go into the differences between these operators here, but switchMap will work for your case.
Your sample code is very close; you can basically use switchMap instead of map.
function newArticle(article: Article) {
return this.db.get(`select id from user_ids where name = ${article.name}`).pipe(
switchMap(id => this.db.get(`select user from users where user_id = ${id}`)),
switchMap(user => this.db.put(`insert into articles(user_name, title, content) values (${user.name}, ${article.title}, ${article.content}`))
);
}
You may find the code easier to follow if you define separate functions with specific purpose:
function getUserIdForArticle(article: Article): Observable<string> {
return this.db.get(`select id from user_ids where name = ${article.name}`);
}
function getUser(id: string): Observable<User> {
return this.db.get(`select user from users where user_id = ${id}`);
}
function storeArticle(user: User, article: Article): Observable<Article> {
return this.db.put(`insert into articles(user_name, title, content) values (${user.name}, ${article.title}, ${article.content}`);
}
function newArticle(article: Article) {
return getUserIdForArticle(article).pipe(
switchMap(id => getUser(id)),
switchMap(user => storeArticle(user, article))
);
}

rxjs join and filter an observable based on values from a different observable

How do I filter an observable using values from another observable, like an inner join in SQL?
class Item {
constructor(public name: string public category: string) {
}
}
class NavItem {
constructor(public key: string public isSelected: boolean = false) {
}
}
// Build a list of items
let items = of(new Item('Test', 'Cat1'), new Item('Test2', 'Cat2'))
.pipe(toArray());
// Determine the unique categories present in all the items
let navItems = from(items)
.pipe(mergeAll(),
distinct((i:item) => i.category),
map(i=>new NavItem(i.category)),
toArray());
I'm building a faceted search so let's say that in the UI, the "Cat1" NavItem is selected, so I want to produce an observable of all the items that have that category. After filtering down to the selected NavItem, I'm not sure how to bring in the Items, filter them down and spit out only those Items that mach a selected category. Here's what I have:
let filteredItems = navItems.pipe(
mergeAll(),
filter(n => n.isSelected))
// join to items?
// emit only items that match a selected category?
Expected result would be
[{name: 'Test', category: 'Cat1'}]
If I understand correctly, you want to select a certain navItem representing a certain category and then select all the items which have such category.
If this is true, than you can consider to create a function or method such as this
selectedItems(categoryId) {
return items.pipe(filter(item => item.category === categoryId));
}
Once you click the navItem then you raise an event which references the navItem and therefore the category id you are interested. You have then to call selectedItems function and pass the category id you selected. This will return an Observable which emits all the items of the category you have selected.
I finally got back around to looking at this and I figured out how to solve this. I needed to use switchMap to join the observables together in the same context. Then I can use map to emit all relevant items:
let filteredItems = from(items)
.pipe(mergeAll(),
switchMap((i) => navItems
// Get only navItems that are selected
.pipe(filter(ni => ni.isSelected),
// Convert back to array so I can if there are any selected items
// if zero, then show all items
toArray(),
map((nav) => {
if(nav.lengh > 0) {
// If the item's category matches, return it
return nav.some(x => x.key == i.category) ? i : null;
}
// If no categories were selected, then show all
return i;
})
}),
// Filter out the irrelevant items
filter(x => x !== null),
toArray()
);

How can I do a WpGraphQL query with a where clause?

This works fine
query QryTopics {
topics {
nodes {
name
topicId
count
}
}
}
But I want a filtered result. I'm new to graphql but I see a param on this collection called 'where', after 'first', 'last', 'after' etc... How can I use that? Its type is 'RootTopicsTermArgs' which is likely something autogenerated from my schema. It has fields, one of which is 'childless' of Boolean. What I'm trying to do, is return only topics (a custom taxonomy in Wordpress) which have posts tagged with them. Basically it prevents me from doing this on the client.
data.data.topics.nodes.filter(n => n.count !== null)
Can anyone direct me to a good example of using where args with a collection? I have tried every permutation of syntax I could think of. Inlcuding
topics(where:childless:true)
topics(where: childless: 'true')
topics(where: new RootTopicsTermArgs())
etc...
Obviously those are all wrong.
If a custom taxonomy, such as Topics, is registered to "show_in_graphql" and is part of your Schema you can query using arguments like so:
query Topics {
topics(where: {childless: true}) {
edges {
node {
id
name
}
}
}
}
Additionally, you could use a static query combined with variables, like so:
query Topics($where:RootTopicsTermArgs!) {
topics(where:$where) {
edges {
node {
id
name
}
}
}
}
$variables = {
"where": {
"childless": true
}
};
One thing I would recommend is using a GraphiQL IDE, such as https://github.com/skevy/graphiql-app, which will help with validating your queries by providing hints as you type, and visual indicators of invalid queries.
You can see an example of using arguments to query terms here: https://playground.wpgraphql.com/#/connections-and-arguments

Why session.getSaveBatch() is undefined when child record was added - Ext 5.1.1

Well the title says it all, details following.
I have two related models, User & Role.
User has roles defined as:
Ext.define('App.model.security.User', {
extend: 'App.model.Base',
entityName: 'User',
fields: [
{ name: 'id' },
{ name: 'email'},
{ name: 'name'},
{ name: 'enabled', type: 'bool'}
],
manyToMany: 'Role'
});
Then I have a grid of users and a form to edit user's data including his roles.
The thing is, when I try to add or delete a role from the user a later call to session.getSaveBatch() returns undefined and then I cannot start the batch to send the modifications to the server.
How can I solve this?
Well after reading a lot I found that Ext won't save the changed relationships between two models at least on 5.1.1.
I've had to workaround this by placing an aditional field on the left model (I named it isDirty) with a default value of false and set it true to force the session to send the update to the server with getSaveBatch.
Later I'll dig into the code to write an override to BatchVisitor or a custom BatchVisitor class that allow to save just associations automatically.
Note that this only occurs when you want to save just the association between the two models and if you also modify one of the involved entities then the association will be sent on the save batch.
Well this was interesting, I've learned a lot about Ext by solving this simple problem.
The solution I came across is to override the BatchVisitor class to make use of an event handler for the event onCleanRecord raised from the private method visitData of the Session class.
So for each record I look for left side entities in the matrix and if there is a change then I call the handler for onDirtyRecord which is defined on the BatchVisitor original class.
The code:
Ext.define('Ext.overrides.data.session.BatchVisitor', {
override: 'Ext.data.session.BatchVisitor',
onCleanRecord: function (record) {
var matrices = record.session.matrices
bucket = null,
ops = [],
recordId = record.id,
className = record.$className;
// Before anything I check that the record does not exists in the bucket
// If it exists then any change on matrices will be considered (so leave)
try {
bucket = this.map[record.$className];
ops.concat(bucket.create || [], bucket.destroy || [], bucket.update || []);
var found = ops.findIndex(function (element, index, array) {
if (element.id === recordId) {
return true;
}
});
if (found != -1) {
return;
}
}
catch (e) {
// Do nothing
}
// Now I look for changes on matrices
for (name in matrices) {
matrix = matrices[name].left;
if (className === matrix.role.cls.$className) {
slices = matrix.slices;
for (id in slices) {
slice = slices[id];
members = slice.members;
for (id2 in members) {
id1 = members[id2][0]; // This is left side id, right side is index 1
state = members[id2][2];
if (id1 !== recordId) { // Not left side => leave
break;
}
if (state) { // Association changed
this.onDirtyRecord(record);
// Same case as above now it exists in the bucket (so leave)
return;
}
}
}
}
}
}
});
It works very well for my needs, probably it wont be the best solution for others but can be a starting point anyways.
Finally, if it's not clear yet, what this does is give the method getSaveBatch the ability to detect changes on relationships.

Resources