How many nested options can node-red handle? - node.js

I was wondering if there is a maximum addressing depth for json formatted files in node-red.
For instance, I have a message like this
{ topic: 'i/devices/i/up',
payload:
{ payload: 'oo',
port: 2,
counter: 54,
metadata:
[ { frequency: 868.3,
datarate: 'SF12BW125',
codingrate: '4/5',
gateway_timestamp: 4201744244,
channel: 1,
server_time: '2016-07-01T09:50:39.725658999Z',
rssi: -63,
lsnr: 8.2,
rfchain: 1,
crc: 1,
modulation: 'LORA',
gateway_eui: 'oo',
altitude: 0,
longitude: 0,
latitude: 0 } ] },
qos: 2,
retain: false,
_msgid: '81960b41.7e69f8',
metadata: <Buffer 00> }
if I wan to get metadata option, I was addressing it within a function in node red like
msg.payload.rssi = msg.payload.metadata["rssi"];
return msg;
However, when I attach a debug function to it, I don't get the rssi value that I want, what am I doing wrong? Cannot that field be addressed like that?
Thanks in advance
regards

There is no limit to the depth of a JSON object you access.
You've missed out an array index out of the selector.
What you need is:
msg.payload.rssi = msg.payload.metadata[0].rssi;
return msg;
This is because the metadata object is an array so could hold multiple instances of the metadata objects.
Also be aware that the debug tab in the Node-RED editor will truncate longer objects, if you need to see the whole object it is easiest to check the "output to console" box and the whole message will be printed to the console as well.

Related

Array of Structs returning unusual data in Solidity

I am creating one Voting Smart Contract people can organize one election and voters can vote for their candidate. I have created one function which will return the statistics of ongoing or past elections
///#dev making statistics for all ballot/election
///#return results with all the information of all
function getStatisticsOfAllVote()
public
view
returns (SingleElectionStatistics[] memory )
{
SingleElectionStatistics[] memory results = new SingleElectionStatistics[](BallotArray.length);
for (uint256 i = 0; i < BallotArray.length; i++) {
SingleElectionStatistics memory temp = SingleElectionStatistics(
BallotArray[i]._getName(), //CEO election
BallotArray[i]._getDescription(),//Employees will choose their CEO
BallotArray[i]._getTotalVoteCounted(),//BigNumber { value: "1" }
BallotArray[i]._isVotingEnded(),//true
BallotArray[i]._getWinningProposalName()//John
);
results[i] = temp;
}
return results;
}
Sample returns are added as comments after the function call.
I suppose to get one array of objects. Buts it gave me data unusual format with extra data. Here are the returns data:
[
[
'CEO election',
'Employees will choose their CEO',
BigNumber { value: "1" },
true,
'John',
name: 'CEO election',
description: 'Employees will choose their CEO',
voteCounted: BigNumber { value: "1" },
voteEnded: true,
winningProposalName: 'John'
]
]
Which should return only
[
{
name: 'CEO election',
description: 'Employees will choose their CEO',
voteCounted: BigNumber { value: "1" },
voteEnded: true,
winningProposalName: 'John'
}
]
I may need help from the community. Thanks in advance
I tried with unit tests and also by changing the approaches but it doesn't help at all.
The raw data returned from a node (using eth_call RPC method) is an ABI-encoded byte array, containing each item just once.
The duplication that you see is caused by an offchain framework. Based on other context, I'm assuming that you're using ethers.js.
Their docs page says:
A Result is an array, so each value can be accessed as a positional argument.
Additionally, if values are named, the identical object as its positional value can be accessed by its name.
In your case, the call returns an array of Result types. Since the Solidity return variables are named (your ethers.js instance knows this from the ABI JSON generated during Solidity compilation), each Result type contains both number-indexed and named items.

Why is the JSON output different from the actual output as rendered in the browser? [duplicate]

I have a problem with logging out the contents of an array inside an object. The actual object looks like this
var stuff = { accepted: [ 'item1', 'item2' ],
rejected: [],
response: 'Foo',
envelope: { from: 'The sender', to: ['new item1', 'new item2'] },
messageId: 'xxxxxxxxxxxxx' } }
The console.log shows the items of the first array fine but the second array is being output as [Object].
{ accepted: [ 'item1', 'item2' ],
rejected: [],
response: 'Foo',
envelope: { from: 'The sender', to: [Object] },
messageId: 'xxxxxxxxxxxxx' } }
What is happening here and how can I get the items of the second array to show when I console.log. Thanks for any help!
UPDATE
Sorry, I forgot to add that I am working exclusively in Node.js so it's a server side log that needs to display the object exactly as it's received from a callback with a straight console.log, ie. no further stringify-ing.
I also just tried creating another random object with a similar structure like this.
var objText = {
fun: {
stuff: 'Some stuff',
list: ['this', 'it', 'takes']
}
};
The console.log for the above is:
{ fun: { stuff: 'Some stuff', list: [ 'this', 'it', 'takes' ] } }
This appears to be the same structure to me and yet the console.log works fine so it seems to be perfectly possible in Node to log arrays content even when it's embedded inside and an object inside an outer object.
It looks like this is an old topic, anyway
I've faced the same issue, embedded array printed as [Array].
It is because of console.log in the node.js uses util.inspect for print, the default depth is 2.
So, to print something which is deeper than 2 followings can be used:
const util = require('util')
console.log(util.inspect(errors, true, 10))
This is the default way for some browser and implementations of showing too complex or deep objects/arrays with console.log. An alternative is to use JSON.stringify with console.log:
var stuff = {
accepted: ['item1', 'item2'],
rejected: [],
response: 'Foo',
envelope: {
from: 'The sender',
to: ['new item1', 'new item2']
},
messageId: 'xxxxxxxxxxxxx'
}
console.log(JSON.stringify(stuff, null, 4));
EDIT:
Another alternative is to use console.dir in case you have a too complex or recursive object, see https://stackoverflow.com/a/27534731/6051261
Try it with: console.log(JSON.stringify(variable))
If you like Chrome devtools, that folds your json objects and let you observe a lot of things, you can use the --inspect flag:
node --inspect index.js
The console will then give you an URL and you just have to copy paste in Google Chrome to enjoy Google Chrome console.
More information on this link

Vuex State of an Array of Array is undefined

I have a store on Vuex with a socket listener.
This listener add to the state messages an array of array.
export const store = new Vuex.Store({
state: {
messages: []
},
mutations: {
SOCKET_GET_MESSAGES: (state, data) => {
state.messages[data[0].recipient] = data[0].res
// Data[0].recipient = the id of the recipient
// Data[0].res is an object with a login and a message.
},
}
In my console I can see the structure is correct if I do:
console.log(this.$store.state.messages)
with this output:
[__ob__: Observer]
2: Array(5)
> 0: {login: "w", message: "ABCD", id: 65}
> 1: {login: "w", message: "Deux", id: 66}
> 2: {login: "w", message: "Quatre", id: 67}
> 3: {login: "w", message: "J'envoie au deux", id: 69}
> 4: {login: "w", message: "Test", id: 70}
length: 5
__proto__: Array(0)
length: 3
__ob__: Observer {value: Array(3), dep: Dep, vmCount: 0}
__proto__: Array
But if I ask a specific ID I get undefined in my console log.
For example I ask for my first user with a message :
console.log(this.$store.state.messages[2])
Do you know how to solve this issue ?
I read lot of stuff on stackoverflow and on vuex documentation but I don't find an answer.
Thank you in advance for your help.
You're modifying the array directly, without using any actual method to do so. Therefore Vue cannot pick up the change you've done. You need to either use push or some other Vue helpers like $set. Quoting some helper docs:
When you modify an Array by directly setting an index (e.g. arr[0] = val) or modifying its length property. Similarly, Vue.js cannot pickup these changes. Always modify arrays by using an Array instance method, or replacing it entirely. Vue provides a convenience method arr.$set(index, value) which is syntax sugar for arr.splice(index, 1, value).
Also, here's a list of all supported mutation methods (wrapped by Vue):
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
Thank you everyone,
After some research I want complete the answer of Andrey Popov.
Indeed if we use Vuex we need to use directly:
Vue.set(state.object, key, data)
The this.$set method is not available in Vuex.
It's now working with this method.

Replacing an object in an object array in Redux Store using Javascript/Lodash

I have an object array in a reducer that looks like this:
[
{id:1, name:Mark, email:mark#email.com},
{id:2, name:Paul, email:paul#gmail.com},
{id:3,name:sally, email:sally#email.com}
]
Below is my reducer. So far, I can add a new object to the currentPeople reducer via the following:
const INITIAL_STATE = { currentPeople:[]};
export default function(state = INITIAL_STATE, action) {
switch (action.type) {
case ADD_PERSON:
return {...state, currentPeople: [ ...state.currentPeople, action.payload]};
}
return state;
}
But here is where I'm stuck. Can I UPDATE a person via the reducer using lodash?
If I sent an action payload that looked like this:
{id:1, name:Eric, email:Eric#email.com}
Would I be able to replace the object with the id of 1 with the new fields?
Yes you can absolutely update an object in an array like you want to. And you don't need to change your data structure if you don't want to. You could add a case like this to your reducer:
case UPDATE_PERSON:
return {
...state,
currentPeople: state.currentPeople.map(person => {
if (person.id === action.payload.id) {
return action.payload;
}
return person;
}),
};
This can be be shortened as well, using implicit returns and a ternary:
case UPDATE_PERSON:
return {
...state,
currentPeople: state.currentPeople.map(person => (person.id === action.payload.id) ? action.payload : person),
};
Mihir's idea about mapping your data to an object with normalizr is certainly a possibility and technically it'd be faster to update the user with the reference instead of doing the loop (after initial mapping was done). But if you want to keep your data structure, this approach will work.
Also, mapping like this is just one of many ways to update the object, and requires browser support for Array.prototype.map(). You could use lodash indexOf() to find the index of the user you want (this is nice because it breaks the loop when it succeeds instead of just continuing as the .map would do), once you have the index you could overwrite the object directly using it's index. Make sure you don't mutate the redux state though, you'll need to be working on a clone if you want to assign like this: clonedArray[foundIndex] = action.payload;.
This is a good candidate for data normalization. You can effectively replace your data with the new one, if you normalize the data before storing it in your state tree.
This example is straight from Normalizr.
[{
id: 1,
title: 'Some Article',
author: {
id: 1,
name: 'Dan'
}
}, {
id: 2,
title: 'Other Article',
author: {
id: 1,
name: 'Dan'
}
}]
Can be normalized this way-
{
result: [1, 2],
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
author: 1
},
2: {
id: 2,
title: 'Other Article',
author: 1
}
},
users: {
1: {
id: 1,
name: 'Dan'
}
}
}
}
What's the advantage of normalization?
You get to extract the exact part of your state tree that you want.
For instance- You have an array of objects containing information about the articles. If you want to select a particular object from that array, you'll have to iterate through entire array. Worst case is that the desired object is not present in the array. To overcome this, we normalize the data.
To normalize the data, store the unique identifiers of each object in a separate array. Let's call that array as results.
result: [1, 2, 3 ..]
And transform the array of objects into an object with keys as the id(See the second snippet). Call that object as entities.
Ultimately, to access the object with id 1, simply do this- entities.articles["1"].
If you want to replace the old data with new data, you can do this-
entities.articles["1"] = newObj;
Use native splice method of array:
/*Find item index using lodash*/
var index = _.indexOf(currentPeople, _.find(currentPeople, {id: 1}));
/*Replace item at index using splice*/
arr.splice(index, 1, {id:1, name:'Mark', email:'mark#email.com'});

Referencing an object array for cascading select options with angular-formly

I'm creating a form which will have field options dependent upon choices earlier in the form, referencing a JSON array. I've studied the Cascade Select example, but haven't quite wrapped my head around how the controllers work in it. Would someone mind helping me adapt the concepts of the Cascade Select example to reference a JSON array?
Here is a link to a JS Bin illustrating what I'm trying to accomplish (be sure to "Run with JS"). I would like fields whose options are populated with respect to an array and are filtered based on previous selection. I've figured out how to do the first level of options for selecting a sport with a simple for-loop function passed to the "options" argument in the form element; but I need a hand moving to the next stage. Ideally, I would like to have more depth; i.e. Pick a Sport > Pick a Team > Pick a Player; but I should be able to figure it out with just the first filtered select options.
Thank you!
Actually this is totally unrelated to angular-formly. Your data model is not properly modeled, you should use the concept of foreign keys. A more appropriate modeling would be:
var sports = [{
id: 1,
name: 'Soccer'
}, {
id: 2,
name: 'Basketball'
}];
var teams = [{
id: 1,
fk: 1,
name: 'Bayern Munich'
}, {
id: 2,
fk: 1,
name: 'Real Madrid'
}, {
id: 3,
fk: 2,
name: 'Cleveland'
}];
var player = [{
id: 1,
fk: 1,
name: 'Mario Götze'
}, {
id: 1,
fk: 2,
name: 'Javier Hernandez'
}, {
id: 2,
fk: 3,
name: 'LeBron James'
}];
A working example is shown here: http://output.jsbin.com/jinaca

Resources