0

I have a table in Mongo DB called 'Business Opportunities'(Check below image). enter image description here

Currently, I am creating node js service where it returns all the matching values for starting letter for business_opportunities field in the table. (highlight one in picture)

So, if i pass 'A' it should only return all the matching ones for letter A in the database but since 'business_opportunities'is an array field it return all the values with matching field like below,

{"status":"success","code":200,"data":{"tags":[{"_id":"5aae9de344fdc45f6a5faf08","business_opportunities":["Web Design","app Design ","Coding","Software Engineer"]},{"_id":"5aae9de344fdc45f6a5faf14","business_opportunities":["audit","Accounting"]},{"_id":"5b86180c44fdc4427245ec71","business_opportunities":["Apps, website, development, programming, php, java, javascript, ruby, react, native","aws cloud services, ","ios, android, "]},{"_id":"5bb70d8c44fdc442dd41b702","business_opportunities":["accounting","quickbooks","xero","cloud accounting","financial","audit","consulting"]},{"_id":"5bbac54944fdc40d9f40f071","business_opportunities":["accommodation","rent","condo"]}]}}

This is my current code,

static async findRelatedTags(opts, params) {
    assert.object(params, 'params')
    assert.string(params.tag, 'params.tag')
    assert.number(params.limit, 'params.limit')

    assert.object(opts, 'opts')
    assert.object(opts.mongo_db, 'opts.mongo_db')

    const { mongo_db: db } = opts

    const query = [
      {
        $match: {
          business_opportunities: { '$regex': '^'+params.tag+'' }
        }
      },
      {
        $project: {
          business_opportunities: '$business_opportunities'
        }
      }
    ]

    const cursor = db.collection('business_opportunities').aggregate([
      ...query
    ]).limit(params.limit)

    return cursor.toArray()
  }

So I want output like this, (if I search 'A')

{
 "status":"success",
 "code":200,
 "data":{
         "tags": [
                   accounting,
                   app design,
                   aws
                  ]
         }
 }
Puneet Singh
  • 3,477
  • 1
  • 26
  • 39

1 Answers1

0

You need to unwind the business_opportunities before matching them with regular expression. Below is the updated code.

static async findRelatedTags(opts, params) {
    assert.object(params, 'params')
    assert.string(params.tag, 'params.tag')
    assert.number(params.limit, 'params.limit')

    assert.object(opts, 'opts')
    assert.object(opts.mongo_db, 'opts.mongo_db')

    const { mongo_db: db } = opts

    const query = [
      { $unwind : "$comments" },
      {
        $match: {
          business_opportunities: { '$regex': '^'+params.tag+'', $options: 'i'  }
        }
      },
      { "$group": {
         "_id": "$comments"
        }
      }
    ]

    const cursor = db.collection('business_opportunities').aggregate([
      ...query
    ]).limit(params.limit)

     var agg_results = cursor.toArray()
     return agg_results.map(obj => obj._id) 
  }

MongoDB aggregation will give you the matched business_opportunities like this

[{
    "_id" : "accounting"
},
{
    "_id" : "app design"
},
{
    "_id" : "aws"
}]

To convert it to ["accounting", "app design", "aws"] I have added agg_results.map(obj => obj._id) in example above.

Except that in your code regex search is Case Sensitive so I have used { '$regex': '^'+params.tag+'', $options: 'i' } to make it Case Insensitive, remove $options if you don't need it.

Puneet Singh
  • 3,477
  • 1
  • 26
  • 39
  • can you help me with these type of values '"accounting ","accounting" . because currently it return both values due to spaces in first word. –  May 13 '20 at 03:55
  • Technically while entering the data in MongoDB it should be trimmed, but now you need to do in node.js, below answers can help you https://stackoverflow.com/questions/25162294/javascript-array-map-with-string-trim https://stackoverflow.com/questions/15125920/how-to-get-distinct-values-from-an-array-of-objects-in-javascript – Puneet Singh May 13 '20 at 04:54