Skip to content
This repository was archived by the owner on Aug 12, 2023. It is now read-only.

Commit 25c7dff

Browse files
authored
Introduce app lookup endpoint (#431)
1 parent 35bb691 commit 25c7dff

File tree

3 files changed

+134
-0
lines changed

3 files changed

+134
-0
lines changed

src/app/routes/v1/app-lookup.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
const _ = require('lodash');
2+
const Router = require('koa-router');
3+
4+
const searchApps = require('../../../apps/search-apps');
5+
6+
const createRouter = () => {
7+
const router = new Router();
8+
9+
router.get('/app-lookup', async ({ request, response }, next) => {
10+
const { q } = request.query;
11+
12+
const limit =
13+
request.query.limit !== undefined ? _.toNumber(request.query.limit) : 5;
14+
const apps = await searchApps(q || null, { limit });
15+
16+
response.body = {
17+
apps,
18+
limit,
19+
q: q || null,
20+
};
21+
22+
await next();
23+
});
24+
25+
return router;
26+
};
27+
28+
module.exports = createRouter;

src/app/routes/v1/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const Router = require('koa-router');
22

33
const createAdSlotsRouter = require('./ad-slots');
44
const createAppRouter = require('./app');
5+
const createAppLookupRouter = require('./app-lookup');
56
const createAppsRouter = require('./apps');
67
const createArticlesRouter = require('./articles');
78
const createArticleSourcesRouter = require('./article-sources');
@@ -28,6 +29,7 @@ const createRouter = () => {
2829
router.use(
2930
createAdSlotsRouter().routes(),
3031
createAppRouter().routes(),
32+
createAppLookupRouter().routes(),
3133
createAppsRouter().routes(),
3234
createArticlesRouter().routes(),
3335
createArticleSourcesRouter().routes(),

src/apps/search-apps.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
const _ = require('lodash');
2+
const moment = require('moment');
3+
4+
const AttributionEntity = require('../model/attribution-entity');
5+
const elasticsearch = require('../util/elasticsearch');
6+
7+
const getSuggestedApps = async limit => {
8+
const response = await elasticsearch.getClient().search({
9+
index: 'fills',
10+
body: {
11+
aggs: {
12+
attributions: {
13+
nested: { path: 'attributions' },
14+
aggs: {
15+
apps: {
16+
filter: {
17+
terms: {
18+
'attributions.type': [0, 1],
19+
},
20+
},
21+
aggs: {
22+
stats_by_app: {
23+
terms: {
24+
field: 'attributions.id',
25+
order: { 'attribution>tradeVolume': 'desc' },
26+
size: limit,
27+
},
28+
aggs: {
29+
attribution: {
30+
reverse_nested: {},
31+
aggs: {
32+
tradeVolume: {
33+
sum: {
34+
field: 'tradeVolume',
35+
},
36+
},
37+
},
38+
},
39+
},
40+
},
41+
},
42+
},
43+
},
44+
},
45+
},
46+
size: 0,
47+
query: {
48+
range: {
49+
date: {
50+
gte: moment()
51+
.subtract(30, 'days')
52+
.toDate(),
53+
},
54+
},
55+
},
56+
},
57+
});
58+
59+
const appBuckets =
60+
response.body.aggregations.attributions.apps.stats_by_app.buckets;
61+
const appIds = appBuckets.map(bucket => bucket.key);
62+
const apps = await AttributionEntity.find({ _id: { $in: appIds } }).lean();
63+
64+
return appBuckets.map(bucket => {
65+
const app = apps.find(a => a._id === bucket.key);
66+
67+
return {
68+
id: app._id,
69+
logoUrl: _.get(app, 'logoUrl', null),
70+
name: app.name,
71+
urlSlug: app.urlSlug,
72+
websiteUrl: _.get(app, 'websiteUrl', null),
73+
};
74+
});
75+
};
76+
77+
function escapeRegex(text) {
78+
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
79+
}
80+
81+
const searchApps = async (query, options) => {
82+
if (query === '' || query === null) {
83+
const suggestedApps = await getSuggestedApps(options.limit);
84+
85+
return suggestedApps;
86+
}
87+
88+
const matchingApps = await AttributionEntity.find({
89+
name: new RegExp(escapeRegex(query), 'ig'),
90+
})
91+
.sort({ name: 1 })
92+
.limit(options.limit)
93+
.lean();
94+
95+
return matchingApps.map(app => ({
96+
id: app._id,
97+
logoUrl: _.get(app, 'logoUrl', null),
98+
name: app.name,
99+
urlSlug: app.urlSlug,
100+
websiteUrl: _.get(app, 'websiteUrl', null),
101+
}));
102+
};
103+
104+
module.exports = searchApps;

0 commit comments

Comments
 (0)