Skip to content

Commit

Permalink
Trendiness Update and Migration Script for New Flyers Model (#106)
Browse files Browse the repository at this point in the history
* Add migration script to update data based on new Flyers schema

* Update Flyer trendiness

* Fix comments

* Clean up syntax for get trending flyers

* Remove unnecessary createSpecificsByIndex function
  • Loading branch information
zachseidner1 authored Sep 14, 2023
1 parent b0976c5 commit d43a4f5
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 63 deletions.
38 changes: 38 additions & 0 deletions migrations/update-flyers-model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module.exports = {
up(db) {
/**
* Updating flyers model to switch to singular organization object and
* singular organization slug
*/
return db.collection('flyers').updateMany({}, [
{
$set: {
organization: { $first: '$organizations' },
organizationSlug: { $first: '$organizationSlugs' },
},
},
{
$unset: ['organizations', 'organizationSlugs'],
},
]);
},

down(db) {
/**
* Reset organizations field to array of size 1 containing current flyer's
* organization. Resets organizationSlugs to an array of size 1 containing
* current flyer's organization slug.
*/
return db.collection('flyers').updateMany({}, [
{
$set: {
organizations: ['$organization'],
organizationSlugs: ['$organizationSlug'],
},
},
{
$unset: ['organization', 'organizationSlug'],
},
]);
},
};
File renamed without changes.
1 change: 0 additions & 1 deletion src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,3 @@ export const IMAGE_ADDRESS = 'https://raw.githubusercontent.com/cuappdev/assets/
export const IOS = 'IOS';
export const MAX_NUM_DAYS_OF_TRENDING_ARTICLES = 30;
export const MAX_NUM_DAYS_OF_FEATURED_MAGAZINES = 30;
export const MAX_NUM_OF_TRENDING_FLYERS = 10;
4 changes: 0 additions & 4 deletions src/entities/Flyer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ export class Flyer {
@Property()
imageURL: string;

@Field()
@Property({ default: false })
isTrending: boolean;

@Field()
@Property()
location: string;
Expand Down
59 changes: 11 additions & 48 deletions src/repos/FlyerRepo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,7 @@ import Filter from 'bad-words';
import { ObjectId } from 'mongodb';

import { Flyer, FlyerModel } from '../entities/Flyer';
import {
DEFAULT_LIMIT,
DEFAULT_OFFSET,
FILTERED_WORDS,
MAX_NUM_DAYS_OF_TRENDING_ARTICLES,
MAX_NUM_OF_TRENDING_FLYERS,
} from '../common/constants';
import { DEFAULT_LIMIT, DEFAULT_OFFSET, FILTERED_WORDS } from '../common/constants';
import { OrganizationModel } from '../entities/Organization';
import utils from '../utils';

Expand Down Expand Up @@ -181,46 +175,16 @@ const searchFlyers = async (query: string, limit = DEFAULT_LIMIT) => {
* @function
* @param {number} limit - number of Flyers to retrieve.
*/
const getTrendingFlyers = async (limit = DEFAULT_LIMIT): Promise<Flyer[]> => {
const flyers = await FlyerModel.find({ isTrending: true }).exec();
return flyers.filter((flyer) => !isFlyerFiltered(flyer)).slice(0, limit);
};

/**
* Refreshes trending Flyers.
*/
const refreshTrendingFlyers = async (): Promise<Flyer[]> => {
// Set previous trending Flyers to not trending
const oldTrendingFlyers = await FlyerModel.find({ isTrending: true }).exec();
oldTrendingFlyers.forEach(async (a) => {
const flyer = await FlyerModel.findById(new ObjectId(a._id)); // eslint-disable-line
flyer.isTrending = false;
await flyer.save();
});

// Get new trending Flyers
const flyers = await (
await FlyerModel.aggregate()
// sort flyers by trendiness
.sort({ trendiness: 'desc' })
// Only get flyers for events that start in the next few days
.match({
startDate: {
$lte: new Date(
new Date().setDate(new Date().getDate() + MAX_NUM_DAYS_OF_TRENDING_ARTICLES),
),
},
})
).slice(0, MAX_NUM_OF_TRENDING_FLYERS);

flyers.forEach(async (a) => {
const flyer = await FlyerModel.findById(new ObjectId(a._id)); // eslint-disable-line
flyer.isTrending = true;
await flyer.save();
});

return flyers;
};
const getTrendingFlyers = async (limit: number = DEFAULT_LIMIT): Promise<Flyer[]> =>
FlyerModel.find({
// Filter by Flyers in the future
endDate: { $gte: new Date() },
})
// Simply select Flyers with the most trendiness
.sort({
trendiness: 'desc',
})
.limit(limit);

/**
* Increments number of times clicked on a flyer by one.
Expand Down Expand Up @@ -312,6 +276,5 @@ export default {
getFlyersByOrganizationSlugs,
getTrendingFlyers,
incrementTimesClicked,
refreshTrendingFlyers,
searchFlyers,
};
1 change: 0 additions & 1 deletion src/tests/data/FlyerFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ class FlyerFactory {
fakeFlyer.endDate = faker.date.future();
fakeFlyer.flyerURL = faker.datatype.string();
fakeFlyer.imageURL = faker.image.cats();
fakeFlyer.isTrending = _.sample([true, false]);
fakeFlyer.location = faker.datatype.string();
fakeFlyer.organization = exampleOrg;
fakeFlyer.organizationSlug = exampleOrg.slug;
Expand Down
49 changes: 40 additions & 9 deletions src/tests/flyer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,17 +191,48 @@ describe('incrementShoutouts tests', () => {

describe('getTrending tests', () => {
test('getTrendingFlyers - get 5 trending flyers', async () => {
const trendingFlyers = await FlyerFactory.createSpecific(5, {
isTrending: true,
});
const notTrendingFlyers = await FlyerFactory.createSpecific(5, {
isTrending: false,
// Shuffle order of trendiness
const randomTrendiness = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].sort(() => Math.random() - 0.5);
// Create flyers with random trendiness
const randomFlyers = await FlyerFactory.create(randomTrendiness.length);
for (let i = 0; i < randomTrendiness.length; i++) {
randomFlyers[i].trendiness = randomTrendiness[i];
}
await FlyerModel.insertMany(randomFlyers);

const trendingFlyers = await FlyerRepo.getTrendingFlyers(randomTrendiness.length);
for (let i = 0; i < randomTrendiness.length; i++) {
expect(trendingFlyers[i].trendiness).toEqual(randomTrendiness.length - i - 1);
}
});
});

describe('getTrending tests', () => {
test('getTrendingFlyers - make sure there are no out of date flyers', async () => {
// Shuffle order of trendiness
const randomTrendiness = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].sort(() => Math.random() - 0.5);
// Create flyers with random trendiness
const randomFlyers = await FlyerFactory.create(randomTrendiness.length);
for (let i = 0; i < randomTrendiness.length; i++) {
randomFlyers[i].trendiness = randomTrendiness[i];
}
const numOfOutOfDateTrendingFlyers = 3;
// Create flyers that are out of date but have high trendiness:
const outdatedFlyers = await FlyerFactory.createSpecific(numOfOutOfDateTrendingFlyers, {
trendiness: 1000,
title: 'outdated',
endDate: new Date().setFullYear(new Date().getFullYear() - 1),
startDate: new Date().setFullYear(new Date().getFullYear() - 1),
});
await FlyerModel.insertMany(trendingFlyers);
await FlyerModel.insertMany(notTrendingFlyers);

const getFlyersResponse = await FlyerRepo.getTrendingFlyers();
expect(getFlyersResponse).toHaveLength(5);
await FlyerModel.insertMany(randomFlyers);
await FlyerModel.insertMany(outdatedFlyers);
const trendingFlyers = await FlyerRepo.getTrendingFlyers(
randomTrendiness.length + numOfOutOfDateTrendingFlyers,
);
for (let i = 0; i < randomTrendiness.length; i++) {
expect(trendingFlyers[i].trendiness).not.toEqual(1000);
}
});
});

Expand Down

0 comments on commit d43a4f5

Please sign in to comment.