#100DaysOfMERN - Day 31

#100DaysOfMERN - Day 31

·

4 min read

✏ How to implement a live search function

Yesterday's plan was to code a recipe database, and in fact I've already built 80% of it, but I've decided against blogging about the whole process. Instead I'll pick certain parts and describe those in detail - like a live search function.

The goal: When I fill out the form to add a new recipe to the database, and start typing into the input field to add an ingredient for this recipe, I'm shown a list of ingredients that are already in the database.

The data structure

I have an Ingredient collection in my database, based on this Schema:

const IngredientSchema = new Schema({
    name: {
        type:String,
        required:true,
        unique:true
    }
}, { timestamps: true });

const Ingredient = mongoose.model('ingredient', IngredientSchema);

module.exports = Ingredient;

The Backend

The server has an API endpoint /api/ingredients, which returns a list of all ingredients in the database, using the .find method on the Model:

app.get('/api/ingredients/', (req, res) => {

        Ingredient.find()
            .then(data => res.json(data))
            .catch(err => console.log(err))
})

I'm going to modify this now, to check first if there's a query string attached to the request. For example, if I make a request to /api/ingredients?search=tom, the search string would be available on the req.query object:

req.query // {search: "tom"}

In that case, the .find method should look for possible matches, and only return those. Conveniently, Mongoose allows passing a RegExpression:

app.get('/api/ingredients/', (req, res) => {

    if (req.query.search) {

        const regex = new RegExp(req.query.search, 'g');

        Ingredient.find({ name: regex})
            .then(data => res.json(data))
            .catch(err => console.log(err))

    } else {
        Ingredient.find()
            .then(data => res.json(data))
            .catch(err => console.log(err))
    }
})

The Frontend

When I type more than two characters into the ingredient field, the onChange handler of the input will trigger an axios GET request to the api/ingredients endpoint, with a query string attached:

    function getIngredients(str){
        axios.get(`/api/ingredients?search=${str}`)
            .then(res => {
                const ingredients = res.data.map(e => e.name);
                setIngredients(ingredients);
            })
            .catch(err => console.log(err))
    }

The response will be an array with all matches, which can then be stored in state, ready for React to display. And indeed - typing "tom" into my input field, I'm shown a match: "Tomato" is already in the database 🍅


✏ Recap

I've learned

  • how to implement a live search function using axios and mongoose

✏ Thanks for reading!

I do my best to thoroughly research the things I learn, but if you find any errors or have additions, please leave a comment below, or @ me on Twitter. If you liked this post, I invite you to subscribe to my newsletter. Until next time 👋


  • Day 1: Introduction, Node.js, Node.js in the terminal

  • Day 2: npm, node_modules, package.json and package-lock.json, local vs global installation of packages

  • Day 3: Create a React app without create-react-app, Webpack, Babel

  • Day 4: npx and cowsay

  • Day 5: npm vs. npx, npm audit, semantic versioning and update rules

  • Day 6: Call stack, event loop, JavaScript engine, JavaScript runtime

  • Day 7: Call stack and event loop in Node.js, setImmediate()

  • Day 8: setImmediate(), process.nextTick(), event loop phases in Node.js

  • Day 9: Network requests with XMLHttpRequest and callbacks

  • Day 10: Promises

  • Day 11: Network requests with XMLHttpRequest and Promises

  • Day 12: React Quiz App part 1

  • Day 13: React Hangman

  • Day 14: FullStackOpen course 1: details of GET and POST requests, request headers

  • Day 15: React Hangman: Trigger fetch with click event callback vs useEffect

  • Day 16: REST API and CRUD

  • Day 17: Boring Book App part 1: React Frontend, Express Backend, GET requests, CORS

  • Day 18: Boring Book App part 2: POST request, File System API

  • Day 19: Boring Book App part 3: Request Parameters, DELETE request

  • Day 20: Boring Book App part 4: PUT request

  • Day 21: Express JS vs Vanilla JS part 1: Server setup, routes

  • Day 22: Express JS vs Vanilla JS part 2: Serve static files with Vanilla Server

  • Day 23: Express JS vs Vanilla JS part 3: Serve static files with Express Server, Middleware

  • Day 24: Express JS: express.Router, Postman

  • Day 25: Express JS: express-handlebars

  • Day 26: MongoDB: Installation, noSQL database structure, Mongo Shell commands

  • Day 27: MongoDB: Project setup, JSON vs BSON, connecting to database, inserting a record

  • Day 28: MongoDB: read and modify data with CRUD operations

  • Day 29: MongoDB with Mongoose: Connecting to the database, Models, Schemas, Saving to the database

  • Day 30: 100DaysOfMERN - App: Backend, Frontend