dopamane
dopamane

Reputation: 1315

How to search each document field individually for specific value?

I have a search bar so that when the user presses enter, the string in the search bar is sent to my ExpressJS server. The server then needs to look through every document in the MongoDB; a document is found if any of its fields matches what was in the search bar.

My current code technically works, but it seems very redundant and probably very inefficient. I use the find() method on each field, saving the matches in an array. After searching each field individually, I prune the array of found matches, removing any duplicates.

Is there a better way to do this? See my current code below:

router.get('/', function(req, res) {
    var regSearch = new RegExp('.*'+searchdata+'.*', 'i'); //Create regular expression of search data -> (text in search bar)
    var arr = [];


    InventoryObject.find({productId: {$regex: regSearch}}).limit(100).exec(function (err, data) {    //Get all docs with a matching productId
      InventoryObject.find({scannerIn: {$regex: regSearch}}).limit(100).exec(function (err, data1) {    //Get all docs with a matching scannerIn
        InventoryObject.find({scannerOut: {$regex: regSearch}}).limit(100).exec(function (err, data2) {    //Get all docs with a matching scannerOut....
          InventoryObject.find({dateIn: {$regex: regSearch}}).limit(100).exec(function (err, data3) {
            InventoryObject.find({dateOut: {$regex: regSearch}}).limit(100).exec(function (err, data4) {
              InventoryObject.find({productName: {$regex: regSearch}}).limit(100).exec(function (err, data5) {
                InventoryObject.find({purchaseOrder: {$regex: regSearch}}).limit(100).exec(function (err, data6) {
                  InventoryObject.find({productDestination: {$regex: regSearch}}).limit(100).exec(function (err, data7) {

                    InventoryObject.find({productCost: parseFloat(searchdata)}).limit(100).exec(function (err, data8) {

                      //Concatenate all matched documents into single array
                      arr = arr.concat(data, data1, data2, data3, data4, data5, data6, data7, data8);

                      //Remove undefined last element...
                      arr.splice(arr.length-1, 1);

                      //Iterate through array and remove any documents that are duplicates 
                      for (var i = 0; i < arr.length; i++) {
                        for (var j = i+1; j < arr.length; j++) {
                          if (arr[i]._id.toString() === arr[j]._id.toString()) {
                            arr.splice(j, 1);
                            j--;
                          }
                        }
                      }

                      //Sort the documents by their _id property
                      arr.sort(function (a, b) {
                        if (a._id < b._id) return +1;
                        if (a._id > b._id) return -1;
                        return 0;
                      });

                      //If the array is longer than 100, truncate it.
                      if (arr.length > 100)
                        arr.length = 100;    //truncate to 100 elements sorted by the order they were inputted

                      //console.log(arr);

                      res.render('index', {'inventoryObjects': arr});
                      searchdata = ''; //Clear search data    
                    });    
                  });    
                });    
              });    
            });    
          });    
        });    
      });
    });
  });

Here is my Schema for reference:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var InventoryObject = new Schema({
    productId: String,
    scannerIn: String,
    scannerOut: String,
    dateIn: String,
    dateOut: String,
    productName: String,
    purchaseOrder: String,
    productDestination: String,
    productCost: Number
});
mongoose.model('InventoryObject', InventoryObject);

Upvotes: 0

Views: 104

Answers (1)

Artem
Artem

Reputation: 410

Unfortunately that's not possible in current Mongo DB versions.

You should optimise your query like this:

InventoryObject.find({
    $or:[
        {productId: {$regex: regSearch}}, 
        {scannerIn: {$regex: regSearch}}, 
        ...
    ]
});

But if you really need to optimise speed of such queries, you should change your schema to something like:

{
    attributes: [
        {key: 'productId', value: 'product ID'},
        {key: 'scannerId', value: 'scanner ID'},
        ...
    ]
}

Upvotes: 2

Related Questions