Home > OS >  MongoDB query: searching array of senteces where there are words from array of single words
MongoDB query: searching array of senteces where there are words from array of single words

Time:06-22

im creating a project where Im using mongoDB and I want to query some recipes.

example of recipe document in my db I want to get recipes where "ingredients" array (sentences), have any words inside matching another array (single words).

I came up with something like this:

const recipes = await recipe
.aggregate([
  
  // add a weight parameter based of number of ingredients matching searched ingredient
  {
    $project: {
      name: 1,
      ingredients: 1,
      tags: 1,
      url: 1,
      weight: {
        $add: [
          {
            $size: {
              $setIntersection: ["$ingredients", ingrArr],
            },
          },
        ],
      },
    },
  },
  { $sort: { weight: -1 } },
])

It shows recipes where there are exact strings like "flour" and I added "weight" to sort them based on number of matching words, however it would not show something like: "cup of flour".

I tried $unwind, but i couldn't make it work. could anybody help me?

CodePudding user response:

document

{
        name: "A Simple Seafood Bisque",
        ingredients: [
            "1 (12 ounce) can evaporated milk",
            "1/2 cup half-and-half",
            "1/2 cup dry white wine",
            "1 roasted red pepper, chopped",
            "2 teaspoons butter",
            "1 bay leaf",
            "1 pinch salt",
            "1 dash hot pepper sauce (such as Tabasco's)",
            "2 (8 ounce) cans oysters, drained and rinsed",
            "2 (6.5 ounce) cans chopped clams with juice",
            "1 cup chopped portobello mushrooms",
            "2 green onions, minced"
        ],
        url: "http://allrecipes.com/recipe/77790/a-simple-seafood-bisque/"

    }

query

const key = 'pepper'
    
db.collection.aggregate(
    {
        $match: {}
    },
    {
        $addFields: {
            weight: {
                $size: {
                    $filter: {
                        input: '$ingredients',
                        as: 'element',
                        cond: {
                            $regexMatch: { input: '$$element', regex: RegExp(key) }
                        }
                    }
                }
            }

        }

    }
)

the result added a field weight with number of matched element

"weight" : 2

or easier way to use $text and $search by create text index at ingredients field and query

db.collection.find( 
    { $text: { $search: "pepper" } },{ score: { $meta: "textScore" } }
   
)

the result added a filed score of search

"score" : 1.1833333333333333

CodePudding user response:

I had to add regular expression array and include it in query. This happens to work like I wanted. thanks

let findString = "";
ingrArr.forEach((e, index) => {
index !== ingrArr.length - 1 ? (findString  = e   "|") : (findString  = e);
});
console.log(findString);
const recipes = await recipe
.aggregate([
  // add a weight parameter based of number of ingredients matching searched 
ingredient
  {
    $addFields: {
      weight: {
        $size: {
          $filter: {
            input: "$ingredients",
            as: "element",
            cond: {
              $regexMatch: {
                input: "$$element",
                regex: RegExp(`${findString}`),
              },
            },
          },
        },
      },
    },
  },
  { $sort: { weight: -1 } },
  • Related