Pushing to array doesn't trigger vue's reactivity - javascript

I already know that editing object within an array doesn't work for vue.js due to its limited capability and base on what I read using vue.set should solve this problem easily but I am having a hard time making it work.
this is my sample data. The parent object is called resource and inside resource there are power_generator_groups , inside the power_generator_groups are power_generators.
{
"id": 5,
"bg_member_id": 1,
"code": "G0633",
"name": "namex1",
"power_generator_groups": [
{
"id": 1,
"resource_id": 5,
"code": "GC033",
"power_generators": [
{
"id": 1,
"power_generator_group_id": 1,
"code": "XXXXX",
"name": "test",
"contract_number": "00000003",
"supply_max": 1000,
},
{
"id": 2,
"power_generator_group_id": 1,
"code": "XXXXX",
"name": "test",
"contract_number": "00000003",
"supply_max": 1000,
},
{
"id": 3,
"power_generator_group_id": 1,
"code": "XXXXX",
"name": "test",
"contract_number": "00000003",
"supply_max": 1000,
}
]
},
{
"id": 2,
"resource_id": 5,
"code": "GC033",
"contract_number": "065C001",
"power_generators": [
{
"id": 4,
"power_generator_group_id": 2,
"code": "XXXXX",
"name": "test",
"contract_number": "00000003",
"supply_max": 1000,
}
]
}
]
}
and this is my vue file
<template lang="pug">
.wrapper
.animated.fadeIn
b-container(fluid='')
b-row.my-1
b-col(sm='3')
label(:for='`type-key`') companyName
b-col(sm='9')
b-form-select(v-model='item.bg_member_id' :options="companyList")
b-col(sm='3')
label(:for='`type-key`') code
b-col(sm='9')
b-form-input(v-model='item.code')
b-button(size='sm', #click='addPowerGeneratorGroup', variant="primary")
| Add power_generator_group
template(v-for='(group, group_index) in item.power_generator_groups')
b-card(
header-tag="header"
footer-tag="footer"
)
div(slot="header")
i.fa.fa-align-justify
strong power_generator_groups
button.btn.btn-default.btn-sm(type='button' #click='deletePowerGeneratorGroup(group_index)')
span.fa.fa-trash-o
div
b-row.my-1
b-col(sm='3')
label(:for='`type-key`')
| code
b-col(sm='9')
b-form-input(v-model='group.code')
b-col(sm='3')
label(:for='`type-key`') group name
b-col(sm='9')
b-form-input(v-model='group.name')
b-col(sm='3')
label(:for='`type-key`') contract number
b-col(sm='9')
b-form-input(v-model='group.contract_number')
b-container.bv-example-row(fluid='')
b-button(size='sm', #click='addPowerGenerator(group_index)', variant="primary")
| add power_generator
b-card(
header-tag="header"
footer-tag="footer"
)
div(slot="header")
i.fa.fa-align-justify
strong power_generators
b-table(small v-bind:item="group.power_generators" v-bind:fields="fields" fixed responsive)
template(v-for="field in fields" :slot="field.key" slot-scope="contract")
template(v-if="field.key == 'actions'")
b-button(size='sm', #click='deletePowerGenerator(group_index, contract.index)', variant="primary")
| Del
template(v-else)
b-form-input(:type='types[field.key]' v-model = 'contract.item[field.key]')
b-button(size='sm', #click='save', variant="primary")
| Save
</template>
<script>
import Vue from 'vue';
export default {
props: {
item: {
type: Object,
required: true,
default: () => {
}
},
companyList: Array
},
data() {
return {
companyId: null,
code: null,
name: null,
contract_number: null,
fields: [
{key: 'actions', label: '' },
{key: 'code', label: 'code', sortable: true, sortDirection: 'desc'},
{key: 'name', label: 'name', sortable: true, class: 'text-center'},
{key: 'contract_number', label: 'contractNo'},
{key: 'supply_max', label: 'maxunit'}
],
types: {
code: 'text',
name: 'text',
contract_number: 'text',
supply_max: 'number'
},
items:
{}
}
},
mounted() {
},
computed: {},
methods: {
addPowerGenerator(index) {
console.log(index)
console.log(this.item)
const pgg = this.item.power_generator_groups[index];
const pgs = pgg.power_generators || Vue.set(pgg, 'power_generators', []);
pgs.push(
{
"code": "",
"name": "",
"contract_number": "",
"supply_max": "",
}
)
},
addPowerGeneratorGroup() {
const pggs = this.item.power_generator_groups || Vue.set(this.item, 'power_generator_groups', []);
pggs.push(
{
"resource_id": this.item.id,
"name": "",
"code": "",
"contract_number": "",
"power_generators": []
}
)
},
deletePowerGenerator(group_index, field_index) {
this.item.power_generator_groups[group_index].power_generators.splice(field_index, 1);
},
deletePowerGeneratorGroup(group_index) {
this.item.power_generator_groups.splice(group_index, 1);
},
save: function () {
this.$parent.save(this.item)
}
}
}
</script>

You'll need Vue.set only if you have power_generator_groups that have no power_generators property, since Vue can't detect when you add it otherwise.
Assuming there are no problems with your template (you didn't show it), change your addPowerGenerator method:
addPowerGenerator(index) {
console.log(index)
console.log(this.item)
const pgg = this.item.power_generator_groups[index];
const pgs = pgg.power_generators || Vue.set(pgg, 'power_generators', []);
pgs.push(
{
"code": "",
"name": "",
"contract_number": "",
"supply_max": "",
}
)
}
Vue.set returns the property you just created which is how pgs contains the proper reference in that case.
Do the same thing for the new method you edited in:
addPowerGeneratorGroup() {
const pggs = this.item.power_generator_groups || Vue.set(this.item, 'power_generator_groups', []);
pggs.push(
{
"resource_id": this.item.id,
"name": "",
"code": "",
"contract_number": "",
"power_generators": []
}
)
}
You can see a mockup here where I've assumed this.item refers to the resource itself. I included a 3rd group which has no power_generators property for testing.

Related

unable to load nested object data in mongoose database properly

The issue I am facing is that even though I am able to load the data in the database but the desired result is different from what is being returned.
The issue is that whenever I am running for loop the qn variable is inserted twice but need it only once.
Please if someone can help me resolve this issue.
userProject.js
router.post('/notification/check/upload/survey' , async (req,res) => {
//const taginsert = [];
const mcq = [];
//const newData = {};
//const o = {};
console.log(req.body);
for(var i=0; i<=req.body.questions.length-1;i++) {
// newData = {
// qn: req.body.questions[i].qn
// }
for(var j=0; j<=req.body.questions[i].options.length-1;j++){
const o =
{
qn: req.body.questions[i].qn,
//{
options: [{
option: req.body.questions[i].options[j].option,
totalValues: req.body.questions[i].options[j].totalValues
}]
}
// newData.options = o;
// newData.push(o);
mcq.push(o);
}
}
//mcq = newData;
const check = new userCampaignSurvey({
userId: req.body.userId,
status: 'Pending',
notification_type:req.body.notification_type,
questions: mcq
})
check.save((err,p) => {
if(err) {
res.status(500).send(err);
}
res.status(201).send(p);
})
})
model.js
userId:
{
type: Number,
required: true,
trim: true
},
notification_id:
{
type: Number,
},
notification_type:
{
type: Number,
required: true,
},
status:
{
type: String,
required: true
},
questions: [
{
qn: {
type: String,
required: true
},
options: [
{
option: {
type: String
},
totalViews: {
type:Number
}
}
]
},
],
created_at: {
type: Date,
required: true,
default: Date.now(),
},
});
result received
{
"userId": 1,
"notification_type": 1,
"status": "Pending",
"questions": [
{
"qn": "Which brand do you like better for buying shoes?",
"options": [
{
"option": "Adidas",
"_id": "639064c9ec215f2cd1b2b15d"
}
],
"_id": "639064c9ec215f2cd1b2b15c"
},
{
"qn": "Which brand do you like better for buying shoes?",
"options": [
{
"option": "Reebok",
"_id": "639064c9ec215f2cd1b2b15f"
}
],
"_id": "639064c9ec215f2cd1b2b15e"
}
],
"created_at": "2022-12-07T10:02:48.442Z",
"_id": "639064c9ec215f2cd1b2b15b",
"__v": 0
}
expected result
{
"userId": 1,
"status": "Pending",
"notification_type": 1,
"questions": [
{
"qn": "Which brand do you like better for buying shoes?",
"options": [
{
"option": "Adidas",
"totalViews": 20
},
{
"option": "Reebok",
"totalViews": 10
}
]
}
]
}

How can I extract innermost value from an array of nested JSON data using their keys?

The following data structure is an array and each array element being an object with keys:
this.objectImWorkingWith = [
{
"1306": {
"id": 6460,
"data": "Process",
},
"1307": {
"id": 6461,
"data": "1287",
},
"1309”: {
"id": 6462,
"data": “2748”,
}
},
{
"1306": {
"id": 6465,
"data": "Product",
},
"1307": {
"id": 6466,
"data": "2574",
},
"1309”: {
"id": 6263,
"data": “3752”,
}
},
{
"1306": {
"id": 6470,
"data": "Research",
},
"1307": {
"id": 6471,
"data": "3861",
},
"1307": {
"id": 6472,
"data": “2248”,
}
}
]
Each element within the array has multiple objects within it and I want to retrieve the value of 'data' for each object within the parent object whilst retaining the structure. Meaning that I want to keep, for example, Process, 1287 and 2748 grouped together and so on.
So in summary I am aiming to get the value of "data" for each object within the array but keep all values of data that are in the same object in the array associated to each other.
I've tried
Object(this.allRelevantData.map(a=>a.data))
however it yields
[undefined, undefined, undefined]
You could try this:
var objectImWorkingWith = [
{
1306: {
id: 6460,
data: "Process",
},
1307: {
id: 6461,
data: "1287",
},
1309: {
id: 6462,
data: "2748",
},
},
{
1306: {
id: 6465,
data: "Product",
},
1307: {
id: 6466,
data: "2574",
},
1309: {
id: 6263,
data: "3752",
},
},
{
1306: {
id: 6470,
data: "Research",
},
1307: {
id: 6471,
data: "3861",
},
1307: {
id: 6472,
data: "2248",
},
},
];
const result = objectImWorkingWith.map((object) => {
const data = [];
for (var key of Object.keys(object)) {
data.push(object[key].data);
}
return data;
});
variable result will contain:
[["Process", "1287", "2748"],
["Product", "2574", "3752"],...]

Recursive replace in hierarchy

I have a JSON tree likes this Github link
As you can see, this tree uses formula property on each item to calculate its value. So I need to calculate the value of a few nodes or root nodes.
You can see PL6A, PL6B is the end of tree with type = 1. So I need to replace up to the tree so which formula construct by PLVALUE must be replaced with ACVALUE.
Example:
PL10 formula must be replace with (ACVALUE(PL6A)+ACVALUE(PL6B))+...
How can I do that, thank you and sorry for bad English
Update
I have tried this code:
for (let i = 0; i < accounts.length; i++) {
const item = accounts[i];
let { formula } = accounts[i];
if (item.children.length && item.type === 2) {
//Replace formula with full children formula
item.children.forEach((child) => {
if (formula.indexOf(child.code) > -1) {
const fullInfoChild = accounts.find(
(fullInfoItem) => _.trim(fullInfoItem._id) === _.trim(child._id)
);
formula = _.replace(
formula,
`PLVALUE(${child.code})`,
`(${fullInfoChild.formula})`
);
}
});
} else {
formula = item.formula;
}
accounts[i].formula = formula;
}
and the result, some node work well
{
"_id": "5cf6159f386f5942aabca347",
"code": "PL10",
"formula": "(ACVALUE(PL6A)+ACVALUE(PL6B))+(ACVALUE(PL9))+(ACVALUE(PL7B)+ACVALUE(PL7A))+(ACVALUE(PL8A)+ACVALUE(PL8B))+(ACVALUE(DSRGP))",
"status": 1,
"type": 2,
"parents": [
{
"_id": "5cf61756386f5942aabca365",
"code": "PL28",
"formula": "PLVALUE(PL10)+PLVALUE(PL15)",
"status": 1,
"type": 2
}
],
"children": [
{
"_id": "5cf614f4386f5942aabca342",
"code": "PL6",
"formula": "ACVALUE(PL6A)+ACVALUE(PL6B)",
"status": 1,
"type": 2
},
{
"_id": "5cf6156a386f5942aabca346",
"code": "PL_DSRGP",
"formula": "ACVALUE(DSRGP)",
"status": 1,
"type": 2
},
{
"_id": "5cf6152f386f5942aabca345",
"code": "PL9",
"formula": "ACVALUE(PL9)",
"status": 1,
"type": 2
},
{
"_id": "5cf6150e386f5942aabca343",
"code": "PL7",
"formula": "ACVALUE(PL7B)+ACVALUE(PL7A)",
"status": 1,
"type": 2
},
{
"_id": "5cf6151e386f5942aabca344",
"code": "PL8",
"formula": "ACVALUE(PL8A)+ACVALUE(PL8B)",
"status": 1,
"type": 2
}
],
"totalCurrentYear": 0
},
but if we up some level it not work like this one
{
"_id": "5cf8c78b4aafe73cb56ce424",
"code": "PL30",
"formula": "(((ACVALUE(PL6A)+ACVALUE(PL6B))+(ACVALUE(PL9))+(ACVALUE(PL7B)+ACVALUE(PL7A))+(ACVALUE(PL8A)+ACVALUE(PL8B))+(ACVALUE(DSRGP)))+((ACVALUE(511000)+ACVALUE(735013)+ACVALUE(511100))+(ACVALUE(511002)+ACVALUE(511101)+ACVALUE(554020)+ACVALUE(735015))+(ACVALUE(511003)+ACVALUE(511102)+ACVALUE(735016))+(ACVALUE(511004)+ACVALUE(554010)+ACVALUE(554021)+ACVALUE(735017)+ACVALUE(554030))))+(PLVALUE(PL23)+PLVALUE(PL24)+PLVALUE(PL25))",
"status": 1,
"type": 2,
"children": [
{
"_id": "5cf61756386f5942aabca365",
"code": "PL28",
"formula": "PLVALUE(PL10)+PLVALUE(PL15)",
"status": 1,
"type": 2
},
{
"_id": "5cf8c7bd4aafe73cb56ce426",
"code": "PL26",
"formula": "PLVALUE(PL23)+PLVALUE(PL24)+PLVALUE(PL25)",
"status": 1,
"type": 2
}
],
},
Updated: Add full json data to github link
You could collect the references to the code/formula and the formulas to replace and iterate the formulas to get the values.
var data = [{ _id: "5cf8c78b4aafe73cb56ce424", code: "PL30", formula: "PLVALUE(PL28)+PLVALUE(PL26)", status: 1, type: 2, children: [{ _id: "5cf61756386f5942aabca365", code: "PL28", formula: "PLVALUE(PL10)+PLVALUE(PL15)", status: 1, type: 2 }, { _id: "5cf8c7bd4aafe73cb56ce426", code: "PL26", formula: "PLVALUE(PL23)+PLVALUE(PL24)+PLVALUE(PL25)", status: 1, type: 2 }] }, { _id: "5cf61756386f5942aabca365", code: "PL28", formula: "PLVALUE(PL10)+PLVALUE(PL15)", status: 1, type: 2, children: [{ _id: "5cf6159f386f5942aabca347", code: "PL10", formula: "PLVALUE(PL6)+PLVALUE(PL9)+PLVALUE(PL7)+PLVALUE(PL8)+PLVALUE(PL_DSRGP)", status: 1, type: 2 }, { _id: "5cf61741386f5942aabca364", code: "PL15", formula: "PLVALUE(PL11)+PLVALUE(PL12)+PLVALUE(PL13)+PLVALUE(PL14)", status: 1, type: 2 }], totalCurrentYear: 0 }, { _id: "5cf6159f386f5942aabca347", code: "PL10", formula: "PLVALUE(PL6)+PLVALUE(PL9)+PLVALUE(PL7)+PLVALUE(PL8)+PLVALUE(PL_DSRGP)", status: 1, type: 2, children: [{ _id: "5cf614f4386f5942aabca342", code: "PL6", formula: "ACVALUE(PL6A)+ACVALUE(PL6B)", status: 1, type: 2 }, { _id: "5cf6156a386f5942aabca346", code: "PL_DSRGP", formula: "ACVALUE(DSRGP)", status: 1, type: 2 }, { _id: "5cf6152f386f5942aabca345", code: "PL9", formula: "ACVALUE(PL9)", status: 1, type: 2 }, { _id: "5cf6150e386f5942aabca343", code: "PL7", formula: "ACVALUE(PL7B)+ACVALUE(PL7A)", status: 1, type: 2 }, { _id: "5cf6151e386f5942aabca344", code: "PL8", formula: "ACVALUE(PL8A)+ACVALUE(PL8B)", status: 1, type: 2 }] }, { _id: "5cf614f4386f5942aabca342", code: "PL6", formula: "ACVALUE(PL6A)+ACVALUE(PL6B)", status: 1, type: 2, children: [{ _id: "5cf61869386f5942aabca368", code: "PL6A", type: 1, status: 1 }, { _id: "5cf6187f386f5942aabca36a", code: "PL6B", type: 1, status: 1 }], totalCurrentYear: 0 }],
replace = (formula, values) => formula.replace(/PLVALUE\(([^\)]+)\)/g, (full, group) => group in values
? `(${values[group].object[values[group].key]})`
: full
),
getNestedValues = (r, object) => {
r.values[object.code] = { object, key: object.type === 1 ? 'code' : 'formula' };
if (object.formula?.includes('PLVALUE')) r.formulas.push(object);
if (object.children) object.children.reduce(getNestedValues, r);
return r;
},
{ values, formulas } = data.reduce(getNestedValues, { values: {}, formulas: [] });
// while (formulas.length) { // only if all targets are known
let i = formulas.length;
while (i--) {
let s = replace(formulas[i].formula, values);
if (s === formulas[i].formula) continue;
formulas[i].formula = s;
formulas.splice(i, 1);
}
// } // only if all targets are known
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Display fetch data in accordion React Native

I'm using an accordion list from native base, and all i'm displaying rightnow is:
const dataArray = [
{ title: "Desc", content: "n" },
{ title: "education1", content: "n" },
{ title: "education2", content: "n" },
{ title: "Price", content: 'n' },
{ title: "place", content: "n" },
{ title: "paiement", content: "n" }
];
...
<Content padder>
<Accordion dataArray={dataArray} expanded={0} />
</Content>
so i fetched some data from a database and i want to diplay the content of every array inside the corresponding accordion pad, here is the format of the data:
Array [
Object {
"code": false,
"id": 10,
"name": "medecin_mediclic",
"presentation": false,
"profession": "Medecin",
"specialite": "Généraliste",
},
Object {
"education": Array [],
},
Object {
"education": Array [],
},
Object {
"price": Array [],
},
Object {
"place": Array [],
},
Object {
"paiement": Array [],
},
]
for example, in my accordion list first pad is "Desc" should contain:
"medecin_mediclic",
false,
"Medecin",
"Généraliste",
and so on.if the array is null then nothing comes out
anyone have any idea how to do it?

Javascript find nested key in a large object

I'm trying to get the value of eth0 nested inside this JSON object
"addresses": {
"eth0": [
"10.0.3.188"
]
},
I was using underscore.js to simplify the process
var _ = require('underscore')._;
var jsonData = {
"plays": [{
"play": {
"id": "d10aae34-6713-4e14-8ad5-fa2fbf6aa2b5",
"name": "lxc"
},
"tasks": [{
"hosts": {
"lxc.server.com": {
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "lxc copy base \"bar69\"",
"delta": "0:00:01.417533",
"end": "2017-01-10 18:01:28.692981",
"invocation": {
"module_args": {
"_raw_params": "lxc copy base \"bar69\"",
"_uses_shell": true,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"warn": true
},
"module_name": "command"
},
"rc": 0,
"start": "2017-01-10 18:01:27.275448",
"stderr": "",
"stdout": "",
"stdout_lines": [],
"warnings": []
}
},
"task": {
"id": "297bf7b7-9ee7-4517-8763-bc3b15baa6e2",
"name": "clone from base"
}
},
{
"hosts": {
"lxc.server.com": {
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "lxc config set \"bar69\" security.privileged true",
"delta": "0:00:00.053403",
"end": "2017-01-10 18:01:32.270750",
"invocation": {
"module_args": {
"_raw_params": "lxc config set \"bar69\" security.privileged true",
"_uses_shell": true,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"warn": true
},
"module_name": "command"
},
"rc": 0,
"start": "2017-01-10 18:01:32.217347",
"stderr": "",
"stdout": "",
"stdout_lines": [],
"warnings": []
}
},
"task": {
"id": "bc63ad6f-1808-48b8-a1de-729153d2b0c5",
"name": "Promote to privileged ct"
}
},
{
"hosts": {
"lxc.server.com": {
"_ansible_no_log": false,
"_ansible_parsed": true,
"actions": [
"start"
],
"addresses": {
"eth0": [
"10.0.3.188"
]
},
"changed": true,
"invocation": {
"module_args": {
"architecture": null,
"cert_file": "/root/.config/lxc/client.crt",
"config": null,
"description": null,
"devices": null,
"ephemeral": null,
"force_stop": false,
"key_file": "/root/.config/lxc/client.key",
"name": "bar69",
"profiles": null,
"source": null,
"state": "started",
"timeout": 30,
"trust_password": null,
"url": "unix:/var/lib/lxd/unix.socket",
"wait_for_ipv4_addresses": true
},
"module_name": "lxd_container"
},
"log_verbosity": 0,
"old_state": "stopped"
}
},
"task": {
"id": "466c0da9-6cbf-4196-aea9-109218c3ed5f",
"name": "Start CT"
}
},
{
"hosts": {
"lxc.server.com": {
"_ansible_no_log": false,
"_ansible_verbose_always": true,
"changed": false,
"invocation": {
"module_args": {
"msg": [
"10.0.3.188"
]
},
"module_name": "debug"
},
"msg": [
"10.0.3.188"
]
}
},
"task": {
"id": "978c490e-59c3-41d2-818d-ab4b557ad803",
"name": ""
}
}
]
}],
"stats": {
"lxc.server.com": {
"changed": 3,
"failures": 0,
"ok": 4,
"skipped": 0,
"unreachable": 0
}
}
}
This is what I have tried so far but no luck!
console.log(_.findKey(_.values(jsonData.tasks)));
Your help is highly appreciated
You could use a few functions like _.pluck() to get the objects at key host, _.property() to see if each host object has a key addresses, .map() to get a mapping of the values, ._filter() to see if a value was returned from the mapping, etc.:
var hosts = _.pluck(jsonData.plays[0].tasks, 'hosts');
var mapping = _.map(hosts, function(host) {
var keys = _.keys(host);
if (_.size(keys)) {
var nestedHost = host[_.first(keys)];
if (_.property('addresses')(nestedHost)) {
if (_.property('eth0')(nestedHost.addresses)) {
return nestedHost.addresses.eth0[0];
}
}
}
});
console.log(_.filter(mapping));
See it in action in this plunker, as well as the example below:
var jsonData = {
"plays": [{
"play": {
"id": "d10aae34-6713-4e14-8ad5-fa2fbf6aa2b5",
"name": "lxc"
},
"tasks": [{
"hosts": {
"lxc.server.com": {
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "lxc copy base \"bar69\"",
"delta": "0:00:01.417533",
"end": "2017-01-10 18:01:28.692981",
"invocation": {
"module_args": {
"_raw_params": "lxc copy base \"bar69\"",
"_uses_shell": true,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"warn": true
},
"module_name": "command"
},
"rc": 0,
"start": "2017-01-10 18:01:27.275448",
"stderr": "",
"stdout": "",
"stdout_lines": [],
"warnings": []
}
},
"task": {
"id": "297bf7b7-9ee7-4517-8763-bc3b15baa6e2",
"name": "clone from base"
}
}, {
"hosts": {
"lxc.server.com": {
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "lxc config set \"bar69\" security.privileged true",
"delta": "0:00:00.053403",
"end": "2017-01-10 18:01:32.270750",
"invocation": {
"module_args": {
"_raw_params": "lxc config set \"bar69\" security.privileged true",
"_uses_shell": true,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"warn": true
},
"module_name": "command"
},
"rc": 0,
"start": "2017-01-10 18:01:32.217347",
"stderr": "",
"stdout": "",
"stdout_lines": [],
"warnings": []
}
},
"task": {
"id": "bc63ad6f-1808-48b8-a1de-729153d2b0c5",
"name": "Promote to privileged ct"
}
}, {
"hosts": {
"lxc.server.com": {
"_ansible_no_log": false,
"_ansible_parsed": true,
"actions": [
"start"
],
"addresses": {
"eth0": [
"10.0.3.188"
]
},
"changed": true,
"invocation": {
"module_args": {
"architecture": null,
"cert_file": "/root/.config/lxc/client.crt",
"config": null,
"description": null,
"devices": null,
"ephemeral": null,
"force_stop": false,
"key_file": "/root/.config/lxc/client.key",
"name": "bar69",
"profiles": null,
"source": null,
"state": "started",
"timeout": 30,
"trust_password": null,
"url": "unix:/var/lib/lxd/unix.socket",
"wait_for_ipv4_addresses": true
},
"module_name": "lxd_container"
},
"log_verbosity": 0,
"old_state": "stopped"
}
},
"task": {
"id": "466c0da9-6cbf-4196-aea9-109218c3ed5f",
"name": "Start CT"
}
}, {
"hosts": {
"lxc.server.com": {
"_ansible_no_log": false,
"_ansible_verbose_always": true,
"changed": false,
"invocation": {
"module_args": {
"msg": [
"10.0.3.188"
]
},
"module_name": "debug"
},
"msg": [
"10.0.3.188"
]
}
},
"task": {
"id": "978c490e-59c3-41d2-818d-ab4b557ad803",
"name": ""
}
}]
}],
"stats": {
"lxc.server.com": {
"changed": 3,
"failures": 0,
"ok": 4,
"skipped": 0,
"unreachable": 0
}
}
};
document.addEventListener('DOMContentLoaded', function() {
var hosts = _.pluck(jsonData.plays[0].tasks, 'hosts');
var mapping = _.map(hosts, function(host) {
var keys = _.keys(host);
if (_.size(keys)) {
var nestedHost = host[_.first(keys)];
if (_.property('addresses')(nestedHost)) {
if (_.property('eth0')(nestedHost.addresses)) {
return nestedHost.addresses.eth0[0];
}
}
}
});
document.getElementById('console').innerHTML = _.filter(mapping);
});
<script data-require="underscore.js#*" data-semver="1.8.3" src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
Address(es):
<div id="console"></div>
You can do this without underscore. An approach you can take is take the given property string and a task, split the property based on the deliminator (you cannot use '.' because you have dotted properties like 'lxc.server.com'), and recursively examine the object until you find the value (or not).
Note: The solutions bellow assume you want to pass a delimited property string but you can just as easily pass an array of props directly and not wrap the helper function.
Tail-cail recursive solution
var jsonData={plays:[{play:{id:"d10aae34-6713-4e14-8ad5-fa2fbf6aa2b5",name:"lxc"},tasks:[{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,changed:!0,cmd:'lxc copy base "bar69"',delta:"0:00:01.417533",end:"2017-01-10 18:01:28.692981",invocation:{module_args:{_raw_params:'lxc copy base "bar69"',_uses_shell:!0,chdir:null,creates:null,executable:null,removes:null,warn:!0},module_name:"command"},rc:0,start:"2017-01-10 18:01:27.275448",stderr:"",stdout:"",stdout_lines:[],warnings:[]}},task:{id:"297bf7b7-9ee7-4517-8763-bc3b15baa6e2",name:"clone from base"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,changed:!0,cmd:'lxc config set "bar69" security.privileged true',delta:"0:00:00.053403",end:"2017-01-10 18:01:32.270750",invocation:{module_args:{_raw_params:'lxc config set "bar69" security.privileged true',_uses_shell:!0,chdir:null,creates:null,executable:null,removes:null,warn:!0},module_name:"command"},rc:0,start:"2017-01-10 18:01:32.217347",stderr:"",stdout:"",stdout_lines:[],warnings:[]}},task:{id:"bc63ad6f-1808-48b8-a1de-729153d2b0c5",name:"Promote to privileged ct"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,actions:["start"],addresses:{eth0:["10.0.3.188"]},changed:!0,invocation:{module_args:{architecture:null,cert_file:"/root/.config/lxc/client.crt",config:null,description:null,devices:null,ephemeral:null,force_stop:!1,key_file:"/root/.config/lxc/client.key",name:"bar69",profiles:null,source:null,state:"started",timeout:30,trust_password:null,url:"unix:/var/lib/lxd/unix.socket",wait_for_ipv4_addresses:!0},module_name:"lxd_container"},log_verbosity:0,old_state:"stopped"}},task:{id:"466c0da9-6cbf-4196-aea9-109218c3ed5f",name:"Start CT"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_verbose_always:!0,changed:!1,invocation:{module_args:{msg:["10.0.3.188"]},module_name:"debug"},msg:["10.0.3.188"]}},task:{id:"978c490e-59c3-41d2-818d-ab4b557ad803",name:""}}]}],stats:{"lxc.server.com":{changed:3,failures:0,ok:4,skipped:0,unreachable:0}}};
function getNestedPropHelper(obj, [first, ...rest]) {
// base case
if (typeof obj !== 'object' || !obj) return undefined;
return rest.length === 0 // if we only have one property
? obj[first] // return the value
: getNestedPropHelper(obj[first], rest); // otherwise recursively return the rest
}
function getNestedProp(obj, prop, delim = '|') {
return getNestedPropHelper(obj, prop.split(delim));
}
// extract the tasks
const tasks = jsonData.plays.reduce((arr, play) => arr.concat(play.tasks), []);
// get the eth0 property for each task
const props = tasks.map(task =>
getNestedProp(task, 'hosts|lxc.server.com|addresses|eth0')
);
// log eth0 properties for each task (only the third one actually has the value)
console.log(props);
You can also do this iteratively, which should usually be faster (although not much in environments that support tail-calls):
Iterative solution
var jsonData={plays:[{play:{id:"d10aae34-6713-4e14-8ad5-fa2fbf6aa2b5",name:"lxc"},tasks:[{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,changed:!0,cmd:'lxc copy base "bar69"',delta:"0:00:01.417533",end:"2017-01-10 18:01:28.692981",invocation:{module_args:{_raw_params:'lxc copy base "bar69"',_uses_shell:!0,chdir:null,creates:null,executable:null,removes:null,warn:!0},module_name:"command"},rc:0,start:"2017-01-10 18:01:27.275448",stderr:"",stdout:"",stdout_lines:[],warnings:[]}},task:{id:"297bf7b7-9ee7-4517-8763-bc3b15baa6e2",name:"clone from base"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,changed:!0,cmd:'lxc config set "bar69" security.privileged true',delta:"0:00:00.053403",end:"2017-01-10 18:01:32.270750",invocation:{module_args:{_raw_params:'lxc config set "bar69" security.privileged true',_uses_shell:!0,chdir:null,creates:null,executable:null,removes:null,warn:!0},module_name:"command"},rc:0,start:"2017-01-10 18:01:32.217347",stderr:"",stdout:"",stdout_lines:[],warnings:[]}},task:{id:"bc63ad6f-1808-48b8-a1de-729153d2b0c5",name:"Promote to privileged ct"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,actions:["start"],addresses:{eth0:["10.0.3.188"]},changed:!0,invocation:{module_args:{architecture:null,cert_file:"/root/.config/lxc/client.crt",config:null,description:null,devices:null,ephemeral:null,force_stop:!1,key_file:"/root/.config/lxc/client.key",name:"bar69",profiles:null,source:null,state:"started",timeout:30,trust_password:null,url:"unix:/var/lib/lxd/unix.socket",wait_for_ipv4_addresses:!0},module_name:"lxd_container"},log_verbosity:0,old_state:"stopped"}},task:{id:"466c0da9-6cbf-4196-aea9-109218c3ed5f",name:"Start CT"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_verbose_always:!0,changed:!1,invocation:{module_args:{msg:["10.0.3.188"]},module_name:"debug"},msg:["10.0.3.188"]}},task:{id:"978c490e-59c3-41d2-818d-ab4b557ad803",name:""}}]}],stats:{"lxc.server.com":{changed:3,failures:0,ok:4,skipped:0,unreachable:0}}};
function getNestedPropHelper(obj, props) {
const isObject = (obj) => typeof obj === 'object' && obj;
if (!isObject(obj)) return undefined;
// keep extracting the properties
for (const prop of props) {
obj = obj[prop];
// of we come across a non-object property before we're done, the property path is invalid
if (!isObject(obj)) return undefined;
}
// if we reached this point, we found the value
return obj;
}
function getNestedProp(obj, prop, delim = '|') {
return getNestedPropHelper(obj, prop.split(delim));
}
// extract the tasks
const tasks = jsonData.plays.reduce((arr, play) => arr.concat(play.tasks), []);
// get the eth0 property for each task
const props = tasks.map(task =>
getNestedProp(task, 'hosts|lxc.server.com|addresses|eth0')
);
// log eth0 properties for each task (only the third one actually has the value)
console.log(props);
Curried recursive solution same approach can be taken for the iterative one
You could also curry the function so you can build getters for certain property paths.
var jsonData={plays:[{play:{id:"d10aae34-6713-4e14-8ad5-fa2fbf6aa2b5",name:"lxc"},tasks:[{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,changed:!0,cmd:'lxc copy base "bar69"',delta:"0:00:01.417533",end:"2017-01-10 18:01:28.692981",invocation:{module_args:{_raw_params:'lxc copy base "bar69"',_uses_shell:!0,chdir:null,creates:null,executable:null,removes:null,warn:!0},module_name:"command"},rc:0,start:"2017-01-10 18:01:27.275448",stderr:"",stdout:"",stdout_lines:[],warnings:[]}},task:{id:"297bf7b7-9ee7-4517-8763-bc3b15baa6e2",name:"clone from base"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,changed:!0,cmd:'lxc config set "bar69" security.privileged true',delta:"0:00:00.053403",end:"2017-01-10 18:01:32.270750",invocation:{module_args:{_raw_params:'lxc config set "bar69" security.privileged true',_uses_shell:!0,chdir:null,creates:null,executable:null,removes:null,warn:!0},module_name:"command"},rc:0,start:"2017-01-10 18:01:32.217347",stderr:"",stdout:"",stdout_lines:[],warnings:[]}},task:{id:"bc63ad6f-1808-48b8-a1de-729153d2b0c5",name:"Promote to privileged ct"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_parsed:!0,actions:["start"],addresses:{eth0:["10.0.3.188"]},changed:!0,invocation:{module_args:{architecture:null,cert_file:"/root/.config/lxc/client.crt",config:null,description:null,devices:null,ephemeral:null,force_stop:!1,key_file:"/root/.config/lxc/client.key",name:"bar69",profiles:null,source:null,state:"started",timeout:30,trust_password:null,url:"unix:/var/lib/lxd/unix.socket",wait_for_ipv4_addresses:!0},module_name:"lxd_container"},log_verbosity:0,old_state:"stopped"}},task:{id:"466c0da9-6cbf-4196-aea9-109218c3ed5f",name:"Start CT"}},{hosts:{"lxc.server.com":{_ansible_no_log:!1,_ansible_verbose_always:!0,changed:!1,invocation:{module_args:{msg:["10.0.3.188"]},module_name:"debug"},msg:["10.0.3.188"]}},task:{id:"978c490e-59c3-41d2-818d-ab4b557ad803",name:""}}]}],stats:{"lxc.server.com":{changed:3,failures:0,ok:4,skipped:0,unreachable:0}}};
function getNestedPropHelper(obj, [first, ...rest]) {
// base case
if (typeof obj !== 'object' || !obj) return undefined;
return rest.length === 0 // if we only have one property
? obj[first] // return the value
: getNestedPropHelper(obj[first], rest); // otherwise recursively return the rest
}
function getNestedProp(prop, delim = '|') {
const props = prop.split(delim);
return function(obj) {
return getNestedPropHelper(obj, props);
}
}
// now you have a getter that will extract eth0 for any task
const getEth0 = getNestedProp('hosts|lxc.server.com|addresses|eth0');
// extract the tasks
const tasks = jsonData.plays.reduce((arr, play) => arr.concat(play.tasks), []);
// extract eth0 from each task
const props = tasks.map(getEth0);
// log eth0 properties for each task (only the third one actually has the value)
console.log(props);
If you want to access it directly, try the following:
jsonData.plays[0].tasks[2].hosts["lxc.server.com"].addresses.eth0[0]
Edit: This was tested. The post that has tasks[3] is incorrect.
We use object-scan for many data processing tasks. It's powerful and fast once you wrap your head around it. Here is how you could solve your question
// const objectScan = require('object-scan');
const find = (input) => objectScan(['**.addresses.eth0[0]'], {
abort: true,
rtn: 'value'
})(input);
const jsonData = { plays: [{ play: { id: 'd10aae34-6713-4e14-8ad5-fa2fbf6aa2b5', name: 'lxc' }, tasks: [{ hosts: { 'lxc.server.com': { _ansible_no_log: false, _ansible_parsed: true, changed: true, cmd: 'lxc copy base "bar69"', delta: '0:00:01.417533', end: '2017-01-10 18:01:28.692981', invocation: { module_args: { _raw_params: 'lxc copy base "bar69"', _uses_shell: true, chdir: null, creates: null, executable: null, removes: null, warn: true }, module_name: 'command' }, rc: 0, start: '2017-01-10 18:01:27.275448', stderr: '', stdout: '', stdout_lines: [], warnings: [] } }, task: { id: '297bf7b7-9ee7-4517-8763-bc3b15baa6e2', name: 'clone from base' } }, { hosts: { 'lxc.server.com': { _ansible_no_log: false, _ansible_parsed: true, changed: true, cmd: 'lxc config set "bar69" security.privileged true', delta: '0:00:00.053403', end: '2017-01-10 18:01:32.270750', invocation: { module_args: { _raw_params: 'lxc config set "bar69" security.privileged true', _uses_shell: true, chdir: null, creates: null, executable: null, removes: null, warn: true }, module_name: 'command' }, rc: 0, start: '2017-01-10 18:01:32.217347', stderr: '', stdout: '', stdout_lines: [], warnings: [] } }, task: { id: 'bc63ad6f-1808-48b8-a1de-729153d2b0c5', name: 'Promote to privileged ct' } }, { hosts: { 'lxc.server.com': { _ansible_no_log: false, _ansible_parsed: true, actions: ['start'], addresses: { eth0: ['10.0.3.188'] }, changed: true, invocation: { module_args: { architecture: null, cert_file: '/root/.config/lxc/client.crt', config: null, description: null, devices: null, ephemeral: null, force_stop: false, key_file: '/root/.config/lxc/client.key', name: 'bar69', profiles: null, source: null, state: 'started', timeout: 30, trust_password: null, url: 'unix:/var/lib/lxd/unix.socket', wait_for_ipv4_addresses: true }, module_name: 'lxd_container' }, log_verbosity: 0, old_state: 'stopped' } }, task: { id: '466c0da9-6cbf-4196-aea9-109218c3ed5f', name: 'Start CT' } }, { hosts: { 'lxc.server.com': { _ansible_no_log: false, _ansible_verbose_always: true, changed: false, invocation: { module_args: { msg: ['10.0.3.188'] }, module_name: 'debug' }, msg: ['10.0.3.188'] } }, task: { id: '978c490e-59c3-41d2-818d-ab4b557ad803', name: '' } }] }], stats: { 'lxc.server.com': { changed: 3, failures: 0, ok: 4, skipped: 0, unreachable: 0 } } };
console.log(find(jsonData));
// => 10.0.3.188
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.8.0"></script>
Disclaimer: I'm the author of object-scan
you can use this code to loop on object properties .
for (key in jsonData){
if(key == "eth0" ){
console.log(jsonData[key].toString())
}
}

Categories