qs icon indicating copy to clipboard operation
qs copied to clipboard

Is there an option to prevent value of the same key being populating into an array?

Open leoyli opened this issue 6 years ago • 10 comments

Hi there,

I'm trying to figure out if qs.parse allow us to update the query key value instead of collecting those as an array from the doc, but I can not find anything about that so I'm asking here.

By default,

qs.parse('?num=1&num=2') === { num: ['1', '2'] };

Instead, I just care about the last value assigned to num in the query. i.e.

qs.parse('?num=1&num=2', { some_option: true }) === { num: '2' };

Is there a some_option to do so?

I'm working on an API and want a consistent way to handle the value. It is annoying to check if the query value is an array for a given key every single time (and it can be an object sometimes)... and at this point I decided to ignore all other value but the latest bound to the key.

But I guess people may also want only the first key value is preserved?! (e.g. that is how StarkOverflow handled their duplicated query key.)

Thanks!

leoyli avatar May 13 '18 08:05 leoyli

One common way it's done is that array keys always have a [] at the end of the name - that's how PHP and Rails do it, for example.

I don't believe there's currently an option to treat duplicate non-array keys as "last one wins" (I don't think "first one wins" would make any sense).

However, since in my experience the most typical webserver setups are:

  1. a=1&a=2 gives a as 2 (a[]=1&a[]=2 gives a as [1, 2])
  2. a=1&a=2 gives a as [1, 2] (a[]=1&a[]=2 gives a as [1, 2])

it seems like a reasonable option to add to parse. For stringify, you'd want the arrayFormat: brackets option (using "repeat" with this new parsing option would lose information).

ljharb avatar May 13 '18 20:05 ljharb

@ljharb Yeah

I see. I currently just added a function to modify the result from qs.parse() in my express app for recursivly handling the last-one-win case (so that I don't need to check if it is a string or array every time, and being safely use string method upon the value of a key).

If add this option is considered, then I actually would suggest to also support first-one-win as an option. It was rarely seemed, but some website does it, e.g. StackOverflow.

leoyli avatar May 13 '18 21:05 leoyli

There should also be an option to do the exact opposite, i.e. always create an array. That would make code easier that expects 1 or more values for an option - currently I need to check if it's an array and otherwise create one from it.

ThiefMaster avatar Oct 02 '18 10:10 ThiefMaster

@leoyli I would say this should be the default behavior, and an option to always create an array should be added for those that want that... i'm dealing with a prod bug caused by this unexpected behavior right now...

617dev avatar Oct 31 '18 16:10 617dev

I think there should be an arrayFormat for parse the same way it is for stringify, so that you can specify brackets/commas/repeat

As a partial workaround however a repeat option would work too - set it to true by default to avoid breaking changes. Setting it to false will make each same key override the previous one unless it's a bracket. something like this, instead of https://github.com/ljharb/qs/blob/e39c235760b58dfaf3a8b5b18b8ff85331e9ddd0/lib/parse.js#L90-L94

we can do

if (has.call(obj, key) && (bracketEqualsPos !== -1 || options.repeat)) {
  obj[key] = utils.combine(obj[key], val);
} else {
  obj[key] = val;
}

that way

qs.parse('a=1&a=2') === { a: [1, 2] } // same as it is right now
qs.parse('a=1&a=2', { repeat: false }) === { a: 2 }

WDYT?

dreyks avatar Sep 06 '19 08:09 dreyks

@dreyks it makes sense to me to try to make the APIs of parse and stringify more consistent; if you think you could draft a PR with tests that does that for arrayFormat, i'd be happy to review it.

ljharb avatar Sep 06 '19 18:09 ljharb

gonna give it a try when time allows

dreyks avatar Sep 06 '19 18:09 dreyks

#329

dreyks avatar Sep 06 '19 20:09 dreyks

How is this feature going?🧐

hellomrbigshot avatar Jun 11 '20 03:06 hellomrbigshot

How is this feature going?🧐

How is this feature going?🧐

AlanKnightly avatar Jan 25 '22 10:01 AlanKnightly