11

I want to generate a query string for my advanced filter. My object looks as follows:

{
   searchValue: {
     firstName: "John",
     lastName: "Doe",
     postalCode: "3130",
     city: "New York"
   },
    page: 1
 }

I'm using the querystring library to try and format my desired string.

export function updateAdvancedSearchQueryString<T>(props: RouteComponentProps, newValues: T) {
  props.history.push({
    pathname: props.location.pathname,
    search: queryString.stringify(newValues)
  });
}

The output I want to achieve:

/trainers?page=1&searchValue=firstName=John&lastName=Doe&postalCode=3130&city=New_York

The output I'm currently getting with this:

/trainers?page=1&searchValue=%5Bobject%20Object%5D

How can I generate my desired querystring from the nested object?

Dax
  • 767
  • 4
  • 11
  • 29
  • One way to turn objects into nicely predictable arrays, which you can then join however you like, is to use `Object.keys()` and then mapping the result to whatever form you need. For instance: ```Object.keys(searchValue).map(val => `key=${searchValue[key]`)```, which you can then join on `&` and now you're suspiciously close to a query string. – Mike 'Pomax' Kamermans Feb 27 '19 at 19:07

2 Answers2

12

You can have many levels of nesting so you should do it recursively.

Something like this shoud be fine

const data = {
  searchValue: {
    firstName: "John",
    middleInitial: null,
    lastName: "Doe",
    postalCode: "3130",
    city: "New York"
  },
  page: 1
}

const createQueryString = (data) => {
  return Object.keys(data).map(key => {
    let val = data[key]
    if (val !== null && typeof val === 'object') val = createQueryString(val)
    return `${key}=${encodeURIComponent(`${val}`.replace(/\s/g, '_'))}`
  }).join('&')
}

console.log(createQueryString(data))

But you have to consider cases in with you pass some object with function as one of it's value, how you will handle arrays things like that. But the basic idea is simple: if you find object as the value use the same function to turn it into querystring

SMAG
  • 652
  • 6
  • 12
Maciej Kozieja
  • 1,812
  • 1
  • 13
  • 32
  • if the val is null then the typeof check will pass and null will become the data of the next recursion. Recommend adding a check for null `val !== null &&` before firing off the recursion. – SMAG Mar 02 '21 at 18:01
  • try this: ```{ AND: [{ NOT: { roles: { has: 'promoter'}, id: { $oid: employeeFormState.id}} }, { country: employeeFormState.country}] }}```, will fail – James Tan Sep 04 '22 at 17:19
1

It was my problem as a beginner in Nodejs and React development. After spending few days I realized that qs library does it very well.

You need to import it

import qs from "qs";

And then use in in client application in my case React:

query = {
   find:{
      sec1:"hi",
      sec2:"there",
   }, 
   limit:12,
   sort:{sec1:-1},
};
const qsg = qs.stringify(query); 
const res = await axios.get(`/api/data?${qsg}`);
console.log("Data from server:", res.data);

And in Nodejs application:

const sendData = asyncHandler(async (req, res) => {
console.log("req.query:", req.query);
const {find, sort, limit, ...rest} = req.query
//optimize the query or deconstruct the request

//run the query in my case Mongoose:
const data = await dataModel
.find(find)
.sort(sort)
.limit(limit);

if (data) {
   res.json(data);
} else {
   res.status(404).json({ message: "data not found" });
   res.status(404);
   throw new Error("Data not found");
}
Amiri
  • 2,417
  • 1
  • 15
  • 42