http://domain.com/action?params[]=1¶ms[]=2¶ms[]=3
returns:
query: { 'params[]': [ '1', '2', '3' ] }
params[] as name instead of params?
After PHP it's kinda surprise.
jQuery serialization is adding [] on parameters btw.
Are you guys wrote a helper for this or I'm just doing it wrong?
This seems like expected behavior to me; I would be more surprised if the querystring parser removed part of the name. That is, the module is doing exactly what I would expect from a parser which simply splits name/value pairs by '&' and name/value by '=' (and unescapes special characters).
var qs = require('querystring');
qs.parse('params=1¶ms=2¶ms=3'); // Name should be "params"
// => { 'params': ['1', '2', '3'] }
qs.parse('params[]=1¶ms[]=2¶ms[]=3'); // Name should be "params[]"
// => { 'params[]': ['1', '2', '3'] }
This module does parsing as required:
https://github.com/visionmedia/node-querystring
There is another one for complex arrays if this doesn't work:
https://github.com/jazzychad/querystring.node.js
Both found here:
https://github.com/joyent/node/wiki/modules
Related
In the application generating dummy data every second and when I log it with "req.body" the output as below.
[
{
dataType: 'Number',
deviceName: 'device1',
attributeName: 'value',
min: '1',
max: '11',
value: '9.000438216772668',
ESP_OPS: 'i',
timestamp: '2020-05-28T20:08:56.544Z'
}
]
However I would like to get "value" in this array. When I try to log it with "req.body.value" it returns "undefined". How can I catch "value" in this array?
req.body returns an array. In this case the array only has 1 element (which is the json object that you want access to). In JavaScript array indices start at 0, therefore you need to writereq.body[0]
Just use req.body[0].value
The [0] statement have the function to reference the first element of the array.
Given this map
r = {
'items': [
{
'id': '1',
'name': 'foo'
},
{
'id': '2',
'name': 'bar'
}
]
}
I am trying to get the 'id' for 'name'=='foo'. I have this:
Id = [api['id'] for api in r['items'] if 'foo' in api['name']]
But then Id == ['1']. I want it to = "1". I can do this:
Id = [api['id'] for api in r['items'] if 'foo' in api['name']][0]
But that seems like a workaround. Is there a way to write that in such a way as to pass only the value of api['id'] rather than the value within a list?
You can use a generator:
Id = next(api['id'] for api in r['items'] if api['name'] == 'foo')
The added benefit is that the iteration will be stopped as soon as you encounter matching object, whereas your original code would process all of the original list and create a new one, only to extract its first element.
The documentation for node module dbus-native is weak, and the none of the many examples apply to my use case, which seems like it ought to be simple.
My problem is trying to make a simple method call into the "connman" network manager. I can make a request (invoking GetProperties method) just fine, and get a complex structure back and generally figure out how to get data out of it. But when I try to send something back with SetProperty, I just can't figure out how to get my data into the form it wants.
There's not really any documentation about how to translate to and from DBus's type system and node's. I gathered from source that variant types are arrays with signature and value, e.g., [ 's', 'string ], but no matter how I try to massage the data I'm trying to send to SetProperty, I get an "Invalid struct data" error.
The SetProperty method I'm trying to call has an argument signature "sv"--name, value. The particular property I'm trying to set has a value with is itself (as far as I can determine--there's precious little documentation on that side as well) an "a{sv}". that is,property is a hash of property names and values. My initial attempt as calling this function was:
var sysbus = require('dbus-native').systemBus();
sysbus.invoke({
path: '/net/connman/service/ethernet_1cba8cfa0e57_cable',
destination: 'net.connman',
'interface': 'net.connman.Service',
member: 'SetPropertry',
signature: 'sv',
body: [
'IPv4.Configuration', [
'a{sv}',
{ 'Method': [ 's', 'dhcp' ] }
]
],
type: dbus.messageType.methodCall
}, function (err, res) {
// etc...
});
This gives me the "Invalid struct data" error. I've tried man other ways to wrap the data in arrays, hashes, etc., and just can't seem to find the right answer. I'm trying to emulate this working Python code:
import dbus
bus = dbus.SystemBus()
service = dbus.Interface(bus.get_object("net.connman",
"/net/connman/service/ethernet_1cba8cfa0e57_cable",
"net.connman.Service");
conf = { "Method": make_string_variant("dhcp") }
service.SetProperty("IPv4.Configuration", conf);
Any ideas?
I recently started using dbus-native for connman and also had problems with all the nested arrays. I'll be improving the marshaling/unmarshaling in the fork of the project at https://github.com/Digisoft-tv/node-dbus - you might want to have a look. Hopefully my changes will be accepted up-stream.
Anyway, to get it working now, the format of the parameters you need to pass in is as below:
mgr.CreateSession([ [ 'key', [ 's', 'value' ] ], [ 'key2', [ 'i', 2 ] ] ], '/object/path', function(error, response) {
if (error) {
return console.error('SetProperty error:', error);
}
console.info('SetProperty response', response);
});
The outermost array is the "object" (ARRAY of dict entries).
Each nested array holds a key-value pair (DICT ENTRY). key at index 0 and value at index 1.
The values is a variant, which is always encoded as an array, with "signature" at index 0 and the actual value at index 1.
Hope it helps.
The correct way to encode 'a{sv}' is [ ['string', ['signature', 'value']], ... ]
Arrays ( a ) are encoded as normal JS arrays as well as structs / hashes ( () / {} ). I'll probably add shortcut to allow JS object to be used in place of a{sv} but at the moment input has to be quite verbose.
var sysbus = require('dbus-native').systemBus();
sysbus.invoke({
path: '/net/connman/service/ethernet_1cba8cfa0e57_cable',
destination: 'net.connman',
'interface': 'net.connman.Service',
member: 'SetPropertry',
signature: 'sv',
body: [
'IPv4.Configuration', [
'a{sv}',
[ // a
[ // {
'Method', [ 's', 'dhcp' ] // sv
]
]
]
],
type: dbus.messageType.methodCall
}, function (err, res) {
// etc...
});
I'm using NodeJS 0.10.13. I'm just curious about the behavior of the following code snippet:
> var a = ['1','2','3']
undefined
> a.map(function(){return path.resolve(arguments[0])})
[ '/Users/user/1',
'/Users/user/2',
'/Users/user/3' ]
> a.map(path.resolve)
TypeError: Arguments to path.resolve must be strings
at exports.resolve (path.js:313:15)
> a.map(path.resolve.bind(path)))
TypeError: Arguments to path.resolve must be strings
at exports.resolve (path.js:313:15)
Why is it that the 2nd and 3rd map calls return an error when the array only has strings? Going to the relevant line in NodeJS's source code yields this:
if (typeof path !== 'string') {
throw new TypeError('Arguments to path.resolve must be strings');
} else if (!path) {
continue;
}
Which makes no sense as to why the arguments are not strings. Does anyone have any clue?
The callback to Array.prototype.map is passed three arguments: current element, index, and the array being traversed.
a.map(path.resolve);
a.map now calls path.resolve using a construct similar to this:
path.resolve.call(undefined, element, index, array);
path.resolve([from ...], to) can accept var args. If you go through the source of path.js
for (var i = arguments.length - 1; i >= -1; i--) {
//..irrelevant lines
var path = arguments[i];
if (typeof path !== 'string') {
throw new TypeError('Arguments to path.resolve must be strings');}
else if (!path) {
continue;
}
}
In the first iteration, path is the third argument, which is an Array.
typeof arrayObject !== 'string' evaluates to true and hence the TypeError
This happens because the parameters passed to each call of the mapped function will get not only the actual elment, but also the array index and the whole array.
To see exactly what parameters gets sent to map, try this:
> var a = ['1', '2', '3'];
['1', '2', '3']
> a.map(function() { return arguments});
[ { '0': '1',
'1': 0,
'2': [ '1', '2', '3' ] },
{ '0': '2',
'1': 1,
'2': [ '1', '2', '3' ] },
{ '0': '3',
'1': 2,
'2': [ '1', '2', '3' ] } ]
Since the object sent to the mapped function (path.resolve in this case) is not a string but an object, you get a TypeError.
I've got the following code, but it doesn't seem to work:
var post_req = {
array: [
[ {
param1: 'something',
param2: 123
} ],
[ ],
[ ],
[ {
param2: 'something',
param4: 1234,
param1: 'hello'
} ]
]
};
var data_send = querystring.stringify(post_req);
var request = client.request('POST', '/', headers);
request.end(data_send);
and
if( req.method == 'POST' ) {
req.addListener('data', function(chunk)
{
POST = querystring.parse(chunk);
console.log(POST);
}
}
I end up with 5 sub-arrays, corresponding to the 5 parameters in the objects but with extra '][' characters in their names:
{ array:
[ { '][param1': 'something' }
, { '][param2': '123' }
, { '][param2': 'something' }
, { '][param4': '1234' }
, { '][param1': 'hello' }
]
}
There is a new node package that fixes this: "npm install qs".
https://github.com/ljharb/qs
"query string parser for node supporting nesting, as it was removed from 0.3.x, so this library provides the previous and commonly desired behaviour (and twice as fast)"
If anyone can tell me why it was removed from 0.3.x, I will give you an upvote for your comment. (I want my confidence in Node.js restored.)
To confirm my comment above, node's querystring.stringify function won't handle nested arrays (at the time of writing).
You can see the source of stringify at https://github.com/ry/node/blob/master/lib/querystring.js
Note that it handles one level of arrays but it doesn't recurse. When it finds an array it uses stringifyPrimitive to encode the array's values. You can see that stringifyPrimitive doesn't handle arrays, only number, boolean and string.
As I suggested in my comment, given that you're using a POST request a better idea would be to use JSON encoding for your complex data structure.
Or use https://github.com/visionmedia/node-querystring as suggested by #FriendlyDev
Don't use querystring.parse for recreating a JSON object sent as string. Use instead JSON.parse. And use JSON.stringify instead of querystring.stringify
querystring is useful when you send parameter encoded in the url or when you post a form. But there is no point in using it if you send just one JSON object with all your data.
In your scenario I would dismiss the querystring library and use JSON library, which is already included. It would be cleaner and faster.
http://www.json.org/js.html