1
votes

I'm a bit new with mongo node and express and I'm experiencing some problems. I'm trying to query all products in a db based on certain keywords. Ideally, I want to find one product containing words from a user search and defaulting to a fixed product if none of the words are found to be contained in a collection

Here's my schema setup:

var  express  = require("express"),
    mongoose = require("mongoose");

var productSchema  = new mongoose.Schema({
    name:  String,
    image: String,
    description:  String,
    keywords:  String,
});

module.exports = mongoose.model('Product', productSchema);

My idea is to match users with a product based on their query. Even if they type a full sentence (currently it only works with single words). If there's no product, I want to default to one product in the db. Here's my route setup:

var express  = require("express"),
    Product  =require('../models/product'),
    router   = express.Router();

router.get('/myroute', function(req,res){
// if there's a query
    if(req.query.search){
    const regex = new RegExp(escapeRegex(req.query.search), 'gi'); 
    var regexSearch = {
        "keywords": {
                "$regex": regex
          }
    };
    Product.findOne(regexSearch, function(err, foundProduct){
        if(err){
            console.log('product not found');
        } else{
            res.render('show', {product: foundProduct});
              }
    });

    } else{
          Product.findOne({name: 'defaultP'}, function(err, foundProduct){        
              if(err){
                  console.log(err);
              } else{
                  res.render('show', {product: foundProduct});
              }
          });

      }  

  });

function escapeRegex(text) {
    return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
};

module.exports = router;

Currently everything works fine when I search a keyword that exists (But not a sentence). However, if I search for a sentence or a keyword that's not present in the db, I get an error when rendering:

Cannot read property 'name' of null at eval (eval at (/home/ubuntu/workspace/node_modules/ejs/lib/ejs.js:524:12), :22:33) at returnedFn (/home/ubuntu/workspace/node_modules/ejs/lib/ejs.js:555:17) at tryHandleCache (/home/ubuntu/workspace/node_modules/ejs/lib/ejs.js:203:34) at View.exports.renderFile [as engine] (/home/ubuntu/workspace/node_modules/ejs/lib/ejs.js:412:10) at View.render (/home/ubuntu/workspace/node_modules/express/lib/view.js:128:8) at tryRender (/home/ubuntu/workspace/node_modules/express/lib/application.js:640:10) at EventEmitter.render (/home/ubuntu/workspace/node_modules/express/lib/application.js:592:3) at ServerResponse.render (/home/ubuntu/workspace/node_modules/express/lib/response.js:971:7) at /home/ubuntu/workspace/routes/match.js:20:23 at Query. (/home/ubuntu/workspace/node_modules/mongoose/lib/model.js:3755:16) at /home/ubuntu/workspace/node_modules/mongoose/node_modules/kareem/index.js:277:21 at /home/ubuntu/workspace/node_modules/mongoose/node_modules/kareem/index.js:131:16 at nextTickCallbackWith0Args (node.js:436:9) at process._tickCallback (node.js:365:13)

2
The error is produced because you simply do not check to see if the result of .findOne() actually returned something. When it does not then it is null and you don't check but just blindly send it to the template. I suspect the reason for no result is the "mangling" of the string being done with the .replace(). Not sure what you are intending to do there, but the output to me would seem unlikely to match any "sentence" stored in the database. - Neil Lunn
Hey Neil. I know this is the reason....just confused on how to check the result before sending it to the template. I want to send the product found to the template...if the search terms didn't match to any product then I want to find mydefault product from the db and load it to the template... - Dennis Macharia
if (foundProduct != null) and your else returns a "not found" response. Like I said though the .replace() here makes no sense since it's just appending `\` to the end of each word, and I doubt your data is stored like that. - Neil Lunn
Omg I'm so stupid. I'll be right back. Thanks a bunch - Dennis Macharia
Hey Neil, that was the issue. I was just sending whatever I got to the template. When it was null then I got the error. Thanks a bunch. Does SO have chatrooms? - Dennis Macharia

2 Answers

0
votes

Try this and then put your function escapeRegex inside RegExp.

var regExpr = new RegExp(".*" + req.query.search + ".*", "i");
var regexSearch = {
    "keywords": regExpr
};
0
votes

please follow this, it may helpful to you.

var str = "";
var searchResult = "";

str = new RegExp(".*" + req.query.search + ".*", "i");

searchResult = { "keywords": str };