Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
leoyli opened this issue May 13, 2018 · 10 comments

Comments

@leoyli
Copy link

leoyli commented May 13, 2018

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 leoyli changed the title Is there a option to prevent the same query key being populating as array? Is there a option to prevent value of the same key being populating into an array? May 13, 2018
@leoyli leoyli changed the title Is there a option to prevent value of the same key being populating into an array? Is there an option to prevent value of the same key being populating into an array? May 13, 2018
@ljharb
Copy link
Owner

ljharb commented May 13, 2018

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).

@leoyli
Copy link
Author

leoyli commented May 13, 2018

@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.

@ThiefMaster
Copy link

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.

@617dev
Copy link

617dev commented Oct 31, 2018

@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...

@dreyks
Copy link
Contributor

dreyks commented Sep 6, 2019

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

qs/lib/parse.js

Lines 90 to 94 in e39c235

if (has.call(obj, key)) {
obj[key] = utils.combine(obj[key], val);
} else {
obj[key] = val;
}

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?

@ljharb
Copy link
Owner

ljharb commented Sep 6, 2019

@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.

@dreyks
Copy link
Contributor

dreyks commented Sep 6, 2019

gonna give it a try when time allows

@dreyks
Copy link
Contributor

dreyks commented Sep 6, 2019

#329

@hellomrbigshot

This comment has been minimized.

@AlanKnightly

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants