Extending data of an existing object from an array - javascript

I receive arrays from an API in a JSON format. I want to merge them into the nested array called which consists of objects graphData. How do I extend the data object by one entry?
mounted() {
var i = 0;
const axios = require('axios');
//Usage
axios.get("https://3.11.40.69:9001/app/usageUnitForCustomer/1521/2019-12-30/2020-12-30")
.then(response => {
const time = response.data.event_time; //["2019-12-30T14:06:21.000Z", "2019-12-30T14:06:21.000Z"]
const unit = response.data.unit; //[44.67, 75.89]
for (i = 0; i < 1; i++) {
if (time[i] !== time[i + 1]) {
this.graphData[1].data.time[i] = unit[i];
}
}
})
//Revenue
axios.get("https://3.11.40.69:9001/app/revenueUnitForMachine/345/2019-12-30/2020-12-30")
.then(response => {
const time = response.data.event_time; //["2019-12-30T14:06:21.000Z", "2019-12-30T14:06:21.000Z"]
const unit = response.data.revenue; //[44, 75]
for (i = 0; i < 10; i++) {
if (time[i] !== time[i + 1]) {
this.graphData[0].data.time[i] = unit[i];
}
}
})
},
data() {
return {
graphData: [
{name: 'Revenue', data: {}},
{name: 'Usage', data: {}}
]
}
}
After executing the above code both data objects are still empty.
The outcome looks like this and following error message:
0:
name: "Revenue"
data: Object []
1:
name: "Usage"
data: Object []
Uncaught (in promise) TypeError: Cannot set property '0' of undefined
Expected outcome:
graphData: [
{name: 'Revenue', data: {'2019-12-30T14:06:21.000Z': 448, '2019-12-30T14:06:22.000Z': 44}},
{name: 'Usage', data: {'2019-12-30T14:06:21.000Z': 448, '2019-12-30T14:06:22.000Z': 44}}
]
Has anyone an idea?

One issue I see is that you access time[i] in this.graphData[1].data.time[i] = unit[i]; but it is not defined inside your objects.
Maybe initializing it as an array helps?
data() {
return {
graphData: [
{name: 'Revenue', data: { time: [] }},
{name: 'Usage', data: { time: [] }}
]
}
}
Edit: Ok, after you edited the expected outcome I see another issue.
Can you try setting the value like this?
this.graphData[1].data[time[i]] = unit[i];
Note the extra [] around time[i].

You cannot reach outside variables from within a .then() block. You should be able to make the whole outside block into an async and use await for your axios calls.
Try something like this:
async mounted() {
var i = 0;
const axios = require('axios');
//Usage
const response = await axios.get("https://3.11.40.69:9001/app/usageUnitForCustomer/1521/2019-12-30/2020-12-30");
const time = response.data.event_time;
const unit = response.data.unit;
for (i = 0; i < 1; i++) {
if (time[i] !== time[i + 1]) {
this.graphData[1].data.time[i] = unit[i];
}
}
...
... continue to use await for the rest of your axios calls.

Related

How does if else works?

I'm trying to figure out where my problem comes from in my algorithm.
I am trying to give the information about the connection status of a data sender with its data table.
I have translated it like this:
if new data is received ( new_id different from id_from_last_request) then I set the connection status to "connected" otherwise I set it to "disconnected"
<script>
export default {
data() {
return {
search: '',
tag_id: ['bts_d02c2b7d9098aaa2', 'bts_c077ffaa9098aaa2'],
headers: [
{
text: 'Tags',
align: 'start',
sortable: false,
value: 'name',
},
{ text: 'wifi', value: 'wifi' },
],
val_ia: 0,
desserts: [],
id_memory: [],
}
},
mounted() {
this.CreateTable();
setInterval(this.getDatafor, 1000)
},
methods: {
CreateTable() {
for (let i = 0; i < this.tag_id.length; i++) {
this.desserts.push(
{
name: this.tag_id[i],
},
)
}
},
async getDatafor() {
for (let i = 0; i < this.desserts.length; i++) {
this.val_ia = i;
await Promise.all([this.getAllData()]);
}
},
async getAllData() {
const tag_id_name = encodeURIComponent(this.tag_id[this.val_ia]);
const url = this.$api.getRESTApiUri() + `/all/last_id/${tag_id_name}`;
return fetch(url)
.then(res => res.text())
.then((result) => {
console.log(tag_id_name)
console.log(this.id_memory[this.val_ia]);
console.log(data[0].id)
const b = this.Test(this.id_memory[this.val_ia], data[0].id);
console.log(b)
if(b){
this.desserts[this.val_ia].wifi = 'connecté'
console.log('connecté')
}else{
this.desserts[this.val_ia].wifi = 'déconnecté'
console.log('déconnecté')
}
this.id_memory[this.val_ia] = data[0].id
})
.catch((error) => {
console.log(error)
});
},
Test(x, y) {
const a = x !== y
return a
},
}
}
</script>
Only in case I have no new data
const b = false
here is my console:
I should have the disconnected status only it shows me the connected status
There should be a logical explanation to it but I can't see it..
You are using equality without type coersion (x !== y) in your Test method.
Probably this.id_memory[this.val_ia] and data[0].id have different types - one is number, second one is string or otherwise.
The best solution is to convert those values to the same type before comparing like so:
Test(x,y){
return String(x) !== String(y)
}
Some use cases:
'123' === 123 // false
'123' == 123 // true
When creating my table, I forgot to push variables wifi and bluetooth so they did not update themselves.
CreateTable(){
for(let i = 0; i < this.tag_id.length; i++){
this.desserts.push(
{
name: this.tag_id[i],
wifi: 'déconnecté',
bluetooth: 0,
tension: 0,
courant: 0,
temperature: 0,
acceléromètre: 0,
pression_sys: 0,
pression_dias: 0,
frequence_cardiaque: 0,
taux_oxygène: 0,
},
)
}
},

async await not waiting for object to fill axios.get

I have an object called move_dict and am using the method get_learned_by_pokemon() to fill it. In getPokes() I call the get_learned_by_pokemon() and expect move_dict to be filled. However it is empty.
function move(){
let move_dict = {}
let db_data = JSON.parse(fs.readFileSync('pokes.json', 'utf8'));
async function get_learned_by_pokemon(curr_move, move_dict, current_poke){
response = await axios.get('https://pokeapi.co/api/v2/move/'.concat(curr_move))
let learned_by_pokemons = []
for (let k = 0; k < response.data.learned_by_pokemon.length; k++){
learned_by_pokemons.push(response.data.learned_by_pokemon[k].name)
}
// pass
if (learned_by_pokemons.includes(current_poke)){move_dict[current_poke].pass.push(curr_move)}
// fail
else{move_dict[current_poke].fail.push(curr_move)}
}
function getPokes(){
//iterate through all pokemon
for (let i = 0; i < db_data.length; i++){
let current_poke = db_data[i].name
let moves = db_data[i].moves
move_dict[current_poke] = {pass: [], fail: []}
//iterate through all moves of pokemon
for (let j = 0; j < moves.length; j++){
let curr_move = moves[j]
//get data on current move
get_learned_by_pokemon(curr_move, move_dict, current_poke)
}
}
}
getPokes()
}
I've also used an await before the Axios.get()
. I'd like to know why move_dict is not filling and I'd like to overcome this problem without using a setTimeout()
It looks like the OP begins with a json file describing pokemons. From the code, it looks like the file contains at least the following...
[
{ name: 'nameA', moves: [ 1, 2, 3, ... ] },
{ name: 'nameB', moves: [ 3, 4, 5, ... ] },
...
]
It looks like there's an api endpoint that takes a move ("id or name") and returns, among other things, a list of pokemons that have "learned" that move.
And it looks like the OP aims to produce a dictionary like this...
{
nameA: { pass: [1, 2, ...], fail: [3, 4, ...] },
nameB: { pass: [3, 4, ...], fail: [4, 5, ...] },
...
}
... where the pass and fail arrays moves found in the input file that either are or are not learned moves according to the api.
Since we don't want to call the api redundantly, and since there might be redundant moves in the input file, it 's worthwhile to create an intermediate structure that associates unique moves in the input the pokemons who have learned them, like this...
{ // key is a move id or name, value is an array of pokemon names
1 : [ 'nameA', 'nameB', ... ],
2 : [ 'nameC', 'nameD', ... ],
...
}
So here's how I'd describe the idea in code (not compiled or tested)...
async function get_learned_by_pokemon(move){
const response = await axios.get(`https://pokeapi.co/api/v2/move/${move}`);
return response.data.learned_by_pokemon.map(p => p.name);
}
async function move() {
let db_data = JSON.parse(fs.readFileSync('pokes.json', 'utf8'));
let allMoves = db_data.flat_map(p => p.moves);
let uniqueMoves = [...new Set(allMoves)];
// map move ids to pokemons who learned the moves { moveId: [ 'pokeA', 'pokeB' ...], ...}
let learnedBy = {}
for (let move in uniqueMoves) {
learnedBy[move] = await get_learned_by_pokemon(move);
}
// map pokemon names to a pair of arrays indicating if they have learned their moves (pass) or not (fail)
let move_dict = db_data.reduce((acc, p) => {
let name = p.name;
let pass = p.moves.filter(move => learnedBy[move].includes(name));
let fail = p.moves.filter(move => !learnedBy[move].includes(name));
acc[name] = { pass, fail };
return acc;
}, {});
return move_dict;
}
there are 2 wrong with your code.
1: where do you call getPokes() ?
2: get_learned_by_pokemon is async function so you have to use await if you want to wait for it done

Extract data from object based on key in JavaScript

I am trying to find the property value of an object based on key. I have below function getData which returns the data based on key passed as input parameter.
const getData = (key) => {
let row = {isSelected: true, Data: {Id: '1A', Value: 'LD'}};
return row[key];
}
console.log(getData('Data'));
In normal scenario it is working fine but how can I get the property value from nested object Data.Value.
If I call getData function as getData('Data.Value'), It should return LD.
You can use lodash's _.get() function that returns the value at a path:
const getData = path => {
const row = {isSelected: true, Data: {Id: '1A', Value: 'LD', InnerData: {Id: 1, Value: "Something"}}};
return _.get(row, path);
}
console.log(getData('Data'));
console.log(getData('Data.Value'));
console.log(getData('Data.InnerData.Value'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
I would suggest accessing the nested value like this:
getData("Data").Value
This is what you want. It is not matter how deep is your row. Try this. It would be multilevel nested object too. For example
Data.InnerData.Value...
const getData = (key) =>{
let row = {isSelected: true, Data: {Id: '1A', Value: 'LD', InnerData: {Id: 1, Value: "Something"}}};
var keys = key.split('.');
var res = row;
for(var i=0; i < keys.length; i++){
res = res[keys[i]];
}
return res;
}
console.log(getData('Data.InnerData.Value'));
When you have dynamic object keys you can use javascript Object.keys method.
var data = getData("Data")
var dynamicKeys = Object.keys(data)
for(int i=0; i < dynamicKeys.length; i++){
console.log(data[dynamicKeys[i]])
}
If you are certain that your object goes two level at most, you can try this simple solution
const isObject = (value) => {
return typeof value === 'object' && !Array.isArray(value) && value !== null;
};
const testData = { isSelected: true, data: { id: '1A', value: 'LD' } };
const getData = (key) => {
const keys = key.split('.');
if (isObject(testData[keys[0]])) {
return testData[keys[0]][keys[1]];
}
return testData[keys[0]];
};
console.log(getData('data.id'));

merge array object within array based on same id

Hello I have a 2 variable with object and with a value of array object, in "test" and "test_2" i would like to merge the sku ("test") and feature ("test_2) based on id (as per below). What is the best way to merge, Im thinking of, for the test_2 I convert the feature into value array object ex: feature:[{id:xxx}] first and after that I do the merge, as I try it doesn't work. Hope anyone here can help me. Thank you
const test =
{
sku: [
{id:"282828282", link:"ksksks.com"},
{id:"676867868", link:"lallaa.com"},
{id:"543454554", link:"sssss.com"},
{id:"345473663", link:"fdfsas.com"}
],
}
const test_2 =
{
panels: [
{id:"9328492847", feature: ['282828282']},
{id:"6756734535", feature: ['543454554', '282828282']},
{id:"6545353453", feature: []},
{id:"4353567688", feature: []},
]
}
const test_3 =
{
panels: [
{id:"9328492847", feature: [{id: '282828282', link:"ksksks.com"} ]},
{id:"6756734535", feature: [{id: '543454554', link:"sssss.com"}, {id:'282828282',link:"ksksks.com"}]},
{id:"6545353453", feature: []},
{id:"4353567688", feature: []},
]
}
let skuSet = {};
for (let i = 0; i < test.sku.length; i++) {
if (!skuSet[test.sku[i].id]) {
skuSet[test.sku[i].id] = test.sku[i];
}
}
for (let i = 0; i < test_2.panels.length; i++) {
let current = test_2.panels[i];
for (let j = 0; j < current.feature.length; j++) {
if (skuSet[current.feature[j]]){
current.feature[j] = skuSet[current.feature[j]];
}
}
}
console.log(JSON.stringify(test_2));
Let me know if you have any question regarding above logic.
let skuMap = {};
test.sku.map((skuData) => { skuMap[skuData.id] = skuData })
test_2.panels.map((panelData) => {
panelData.feature = panelData.feature.map((panelFeatureId) => skuMap[panelFeatureId])
})
Simple and fast

Create object from JSON using headers from JSON

I have a JSON object that is similar to below:
vehicles:
{
trucks: [
"Ford",
"Toyota",
"Dodge",
],
suvs: [
"Honda",
"GMC",
],
cars: [
"Pontiac",
"Lotus",
"Aston-Martin",
"Porsche",
"Subaru"
]
}
I would like to loop through this and create my own object, however I cannot find out how to do it without using three different loops for each type of vehicle.
Here is my attempt below:
let vehicleObject = {
vehicles: []
}
// I'm getting the response back from a http request
Object.keys(body.vehicles).forEach(function (k) {
for (let i = 0; i < body.vehicles.k.length; i++) {
vehicleObject.vehicles.push({
vehicle_type: k,
manufacturer: body.vehicles.k[i]
});
}
});
However, this just leads me to "cannot read property length of undefined. I know I can accomplish this with a switch or three if's but I would like to learn a more efficient way, if possible. Thank you.
Loop should be like this:
Object.keys(body.vehicles).forEach(function (k) {
for (let i = 0; i < body.vehicles[k].length; i++) {
vehicleObject.vehicles.push({
vehicle_type: k,
manufacturer: body.vehicles[k][i]
});
console.log(vehicles[k].length)
}
});
When you iterate over each key you are getting name of the keys in k and then to get the array from body.vehicles object you need to do something like body.vehicles[k].
To declare global variable for the scope you should probably use var instead of let
var vehicleObject = {
vehicles: []
};
let is reachable only inside {...} block, like you used it in your for {...} loop.
Looks like you want an array of objects, like:
[{ vehicle_type: 'suvs', manufacturer: 'Honda' }, ... ]
Assuming, body contains the vehicles object:
const { vehicles } = body
const vehicleTypes = Object.keys(vehicles)
const getManufacturers = type => vehicles[type]
const createVehicle = (type, mf) => ({ vehicle_type: type, manufacturer: mf })
let flattenedVehicles = []
vehicleTypes.forEach(type => {
flattenedVehicles.push(
getManufacturers(type).map(mf => createVehicle(type, mf))
)
})
// flattenedVehicles now has desired array

Categories

Resources