Cast My Show

The Idea

Casting hypothetical shows and movies is one of the favourite past times of the theatrically inclined. I knew that I wanted to try using Google Firebase as the backend on a project, and this seemed like a perfect opportunity to build out a fun little app. Users create accounts, search for shows (or add a new play if it doesn't exist), cast a show, and save their casts to their account!

The Tech

I used React to develop the frontend of the site and integrated Firestore as the database. It was my first time working with a NoSQL database, and while I missed some of the advantages of a relational model, the flexibility and scalability of NoSQL are fantastic.

I especially enjoyed working on the drag and drop interface, accessibility for various components, and the search functionality.

The Best Part

My favourite part of working on the app was building out the search functionality. I knew that I need to allow users to find the shows that they were looking for quickly, but one of the tradeoffs of a NoSQL database is that searching can be more complicated.

To solve the problem, I researched common search patterns, especially those using keywords. When a user inputs a new play or musical into the database, I split the title into keywords, filter out stop words, and then create an array on the document. Plus, the user can add keywords of their choosing.

When running a search query, I can use the "array-contains" method within Firestore to retrieve records containing that keyword. It's not a robust solution and might not hold up to scale, but for this project, it works like a charm.

1const handleSubmit = async e => {
2 e.preventDefault();
3 const lowerSearch = search.toLowerCase();
4 const titleSearch = titleCase(search);
5 let results = [];
6
7 let result = await Promise.all([
8 firestore
9 .collection("shows")
10 .where("keywords", "array-contains", lowerSearch)
11 .orderBy("title")
12 .limit(50)
13 .get(),
14 firestore
15 .collection("shows")
16 .where("title", "==", titleSearch)
17 .limit(5)
18 .get(),
19 ]).catch(err => {
20 setErr(err.message);
21 });
22 if (result) {
23 result.map(query => {
24 return query.docs.map(doc => {
25 const data = doc.data();
26 const id = doc.id;
27 return results.push({ ...data, id });
28 });
29 });
30 const finalResult = Array.from(new Set(results.map(show => show.id))).map(
31 id => {
32 return {
33 id: id,
34 ...results.find(show => show.id === id),
35 };
36 }
37 );
38 props.getResults(finalResult, search);
39 }
40};
41
© 2022, Gabe Kirkley