skip to Main Content

If I have a document that looks like this:

{
    "firstName": "John",
    "lastName": "Doe",
    "favoriteFoods": [{"name": "Cheeseburgers"}, {"name": "Broccoli"}]
}

And I want to create a search expression in NodeJS to return just the element’s of favoriteFood name matches req.body.term, how could I implement this? I have tried the code below, but this returns an entire document, which I don’t want because I have to filter the array.

User.find({"favoriteFoods.title": {$regex: req.body.term, $options: "i"}})
        .then((food) => {
            res.status(200).send(food);
        })

2

Answers


  1. You can use Array.filter() to match the values.

    res.status(200).send(food.favoriteFoods
      .filter(food => food.title.match(new RegExp(req.body.term, 'i'))
    );
    

    You used name in the example JSON but title in the code, so make sure you’re using whichever of those is actually correct

    Also, allowing users to specify their own regular expressions could allow for Regex DOS attacks, so be warned of that.

    Login or Signup to reply.
  2. I don’t know at all the desired format result so here you have multiple ways to get that:

    1. Using $elemMatch into the projection stage:
    db.collection.find({},
    {
      "favoriteFoods": {
        "$elemMatch": {
          "name": {
            "$regex": "chee",
            "$options": "i"
          }
        }
      }
    })
    

    But be careful, $elemMatch only return one result. Check this example.

    1. Using $filter into an aggregation stage: This query will return an array called "food" only with objects that matches the regex.
    db.collection.aggregate([
      {
        "$project": {
          "food": {
            "$filter": {
              "input": "$favoriteFoods",
              "cond": {
                "$regexMatch": {
                  "input": "$$this.name",
                  "regex": "chee",
                  "options": "i"
                }
              }
            }
          }
        }
      }
    ])
    

    It will return more than one objecs if they match. Example here

    1. Using $unwind and $match: This query uses $unwind which is not the best step you want to use but it is very useful. Using it with $match and $project you can get the result into an object and not an array (keeping in mind that mongo result is always an array, but each object inside will have food property and will not be an array).
    db.collection.aggregate([
      {
        "$unwind": "$favoriteFoods"
      },
      {
        "$match": {
          "favoriteFoods.name": {
            "$regex": "chee",
            "$options": "i"
          }
        }
      },
      {
        "$project": {
          "food": "$favoriteFoods.name"
        }
      }
    ])
    

    Example here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search