0

I have a Node.js program that is using Mongo Atlas search indexes and is utilizing the Aggregate function inside of the MongoDB driver. In order to search, the user would pass the search queries inside of the query parameters of the URL. That being said, I am trying to build a search object based on if a query parameter exists or not. In order to build the search object I am currently using object spread syntax and parameter short-circuiting, like so:

const mustObj = {
  ...(query.term && {
    text: {
      query: query.term,
      path: ['name', 'description', 'specs'],
      fuzzy: {
        maxEdits: 2.0,
      },
    },
  })
}

This is a shortened version, as there are many more parameters, but you get the jest.

In a MongoDB search query, if you have multiple parameters that must meet a certain criteria, they have to be included inside of an array called must, like so:

{
  $search: {
    compound: {
       must: [],
    },
  },
}

So, in order to include my search params I must first turn my mustObj into an array of objects using Object.keys and mapping them to an array, then assigning the searches 'must' array to the array I've created, like so:

const mustArr = Object.keys(mustObj).map((key) => {
  return { [key === 'text2' ? 'text' : key]: mustObj[key] };
});
searchObj[0].$search.compound.must = mustArr;

What I would like to do is, instead of creating the mustObj and then looping over the entire thing to create an array, is to just create the array using the spread syntax and short-curcuiting method I used when creating the object.

I've tried the below code, but to no avail. I get the 'object is not iterable' error:

const mustArr = [
  ...(query.term && {
    text: {
      query: query.term,
      path: ['name', 'description', 'specs'],
      fuzzy: {
        maxEdits: 2.0,
      },
    },
  })
]

In all, my question is, is what I'm asking even possible? And if so, how?

Doug
  • 14,387
  • 17
  • 74
  • 104
Brandon Miller
  • 1,534
  • 1
  • 11
  • 16
  • 1
    `a=[...({})]` is not possible but `a=[...([{}])]` is possible – Chau Giang Mar 05 '21 at 07:20
  • 1
    I think you can use simple for loop and push your object to `mustArr` – Chau Giang Mar 05 '21 at 07:26
  • 1
    You can try something like this: `mustArr = [query.term? {text: {query: ""}} : {}]`, no need to destructuring – Chau Giang Mar 05 '21 at 07:30
  • @ChauGiang Got me almost there with the first comment. The only problem is I get 'undefined is not iterable' if one of the parameters is missing. Unfortunately I cant to the ternary operator since mongo will throw an error if I send a blank object. – Brandon Miller Mar 05 '21 at 07:38
  • There is no destructuring shown in the question, it's just spread syntax. – VLAZ Mar 05 '21 at 10:32

1 Answers1

2

Corrected based on @VLAZ comment:

while spread with array [...(item)], item has to be array (iterable).

When you use short-circuit, the item as below,

 true && [] ==> will be `[]` ==> it will work 
 false && [] ==> will be `false` ==> wont work (because false is not array)

try some thing like (Similar to @Chau's suggestion)

const mustArr = [
  ...(query.term ? [{
    text: {
      query: query.term,
      path: ['name', 'description', 'specs'],
      fuzzy: {
        maxEdits: 2.0,
      },
    },
  }] : [])
]
Siva K V
  • 10,561
  • 2
  • 16
  • 29
  • Ahhhh! I see. Because I'm destructuring the array it will not return a blank array. Perfect! That worked! Thank you guys so much! – Brandon Miller Mar 05 '21 at 07:53
  • 1
    "*In destructing with array `[...(item)]`, `item` has to be array.*" 1. this is not destructuring but spread. 2. `item` can be any iterable, not just an array. – VLAZ Mar 05 '21 at 10:30