conditionally modify object's property ES6 - ecmascript-6

I have below object in ES6.
const myObject = {
list1: [
{ title:'test1', acted:false, currentAction:false
},
{ title:'test2', acted:false, currentAction:false
},
{ title:'test3', acted:false, currentAction:false
},
{ title:'test3', acted:false, currentAction:false
}],
list2:
[
{ title:'data1', acted:false, currentAction:false
},
{ title:'data2', acted:false, currentAction:false
},
{ title:'data3', acted:false, currentAction:false
},
{ title:'data4', acted:false, currentAction:true,
}],
list3:
[
{ title:'a1', acted:false, currentAction:false
},
{ title:'a2', acted:false, currentAction:false
},
{ title:'a3', acted:false, currentAction:false
},
{ title:'a4', acted:false, currentAction:false,
}],
}
I would like to check if any currentAction property within any list is true make it false and return the whole modified object.
I know how to directly modify object property but not sure about any list within object can be filter and modified.
this is what I tried
const newObject = { ...myObject, currentAction:true }

You tried this code:
const newObject = { ...myObject, currentAction:true }
This won’t filter anything, and it doesn’t come close to what you want. But it does help clarify the question: when you say “return the whole modified object”, apparently you really mean the whole thing:
{
list1: [
{ title:'test1', acted:false, currentAction:false
},
{ title:'test2', acted:false, currentAction:false
},
{ title:'test3', acted:false, currentAction:false
},
{ title:'test3', acted:false, currentAction:false
}],
list2:
[
{ title:'data1', acted:false, currentAction:false
},
{ title:'data2', acted:false, currentAction:false
},
{ title:'data3', acted:false, currentAction:false
},
{ title:'data4', acted:false, currentAction:true,
}],
list3:
[
{ title:'a1', acted:false, currentAction:false
},
{ title:'a2', acted:false, currentAction:false
},
{ title:'a3', acted:false, currentAction:false
},
{ title:'a4', acted:false, currentAction:false,
}],
}
Now let’s answer the question. First, to reset the currentAction properties to false:
for (listIndex = 0; listIndex < 3; ++listIndex) {
for (const innerObject of myObject["list" + listIndex]) {
innerObject.currentAction = false;
}
}
The notation "list" + listIndex is string concatenation. The notation myObject[...] is used to access a property using a computed property name. This gives us an array, which we iterate over using for (const innerObject of ...).
Now, to return the new object: no need, because it’s already in myObject. Even though myObject was declared as a const, that just means that the object reference it contains is constant. In other words, myObject always refers to the same object. But the object itself can change.
Edit: Felix Kling suggested using for (const list of Object.values(myObject)) to iterate over myObject’s properties. This way we don’t make any assumptions about the number of properties or their names. I also renamed innerObject to listItem.
for (const list of Object.values(myObject)) {
for (const listItem of list) {
listItem.currentAction = false;
}
}

Related

JSON only reading first element of array

I am working on a discord bot using Typescript, and I am having a problem reading from the config.JSON file.
This is the read vars function:
fs.readFile('config.json', 'utf8', function readFileCallback(err, data){
if (err){
console.log(err);
} else {
config = JSON.parse(data);
console.log(config);
const store = config.configstore[0];
roster = config.roster[0];
}});
and this is the config.json file:
{
"configstore": [
{"prefix": "!!"},
{"wallTime": 5},
{"bufferTime": 15},
{"wall": "false"},
{"buffer": "false"},
{"lastWallTime": "-1"},
{"lastBufferTime": "-1"},
{"wallCheckRole": "Role"},
{"bubfferCheckRole": "Role"}
],
"roster": [
{"discID":"discordID","ign":"IGN"}
]
}
When I print out the raw 'config' variable it prints this:
{
configstore: [
{ prefix: '!!' },
{ wallTime: 5 },
{ bufferTime: 15 },
{ wall: 'false' },
{ buffer: 'false' },
{ lastWallTime: '-1' },
{ lastBufferTime: '-1' },
{ wallCheckRole: 'Role' },
{ bubfferCheckRole: 'Role' }
],
roster: [ { discID: 'DiscordID', ign: 'IGN' } ]
}
But when I print the store variable it prints this:
{ prefix: '!!' }
The roster is normal as well.
The roles and ids are strings, but I changed it since I don't want them leaked.
These are some examples of what you are probably trying to achieve:
let config1 = {
"configstore": [
{"prefix": "!!"},
{"wallTime": 5},
{"bufferTime": 15},
{"wall": "false"},
{"buffer": "false"},
{"lastWallTime": "-1"},
{"lastBufferTime": "-1"},
{"wallCheckRole": "Role"},
{"bubfferCheckRole": "Role"}
],
"roster": [
{"discID":"discordID","ign":"IGN"}
]
}
let config2 = {
"configstore": [
{
"prefix": "!!",
"wallTime": 5,
"bufferTime": 15,
"wall": "false",
"buffer": "false",
"lastWallTime": "-1",
"lastBufferTime": "-1",
"wallCheckRole": "Role",
"bubfferCheckRole": "Role"
}
],
"roster": [
{"discID":"discordID","ign":"IGN"}
]
}
//prints {"prefix":"!!"}
console.log("configstore1:", JSON.stringify(config1.configstore[0]));
//prints {"discID":"discordID","ign":"IGN"}
console.log("roster1:", JSON.stringify(config1.roster[0]));
//prints {"prefix":"!!","wallTime":5,"bufferTime":15,"wall":"false","buffer":"false","lastWallTime":"-1","lastBufferTime":"-1","wallCheckRole":"Role","bubfferCheckRole":"Role"}
console.log("configstore2:", JSON.stringify(config2.configstore[0]));
//prints {"discID":"discordID","ign":"IGN"}
console.log("roster2:", JSON.stringify(config2.roster[0]));

How to output object of an array in the root of the document in MongoDB using aggregation?

I have this document :
{"_id":"1", "elem":"ok",
"arrayOfObjects":[
{"type":"k","fieldx":"lol"},
{"type":"SndObject","fieldy":"foo"},
{"type":"Object1","fieldx":"bob"}
]
}
what is the aggregation to have this output:
{"_id":"1", "elem":"ok",
"Object1":[
{"type":"Object1","fieldx":"lol"},
{"type":"Object1","fieldx":"bob"}
],
"SndObject":[{"type":"SndObject","fieldy":"foo"}]
}
I found a way out, but it need me to know all the type i have:
{
"$addFields" : {
"Object1" : {
"$filter": {
"input": "$arrayOfObjects",
"as": "types",
"cond": {
"$and": [{ "$eq": [ "$$types.type", "Object1" ] }]
}
}
}
}
}
It would be best if i can loop over my arrayOfObjects and get the same result without pre knowledge of the type.
Might be there would be more easy option than this,
$unwind deconstruct arrayOfObjects array
$group by _id, type and elem, construct array of arrayOfObjects
$arrayToObject convert k and v from array to object
$group by _id and merge objects in root
db.collection.aggregate([
{ $unwind: "$arrayOfObjects" },
{
$group: {
_id: {
type: "$arrayOfObjects.type",
_id: "$_id"
},
elem: { $first: "$elem" },
arrayOfObjects: { $push: "$arrayOfObjects" }
}
},
{
$group: {
_id: "$_id._id",
elem: { $first: "$elem" },
arrayOfObjects: {
$mergeObjects: {
$arrayToObject: [[
{
k: "$_id.type",
v: "$arrayOfObjects"
}
]]
}
}
}
}
])
Playground

How to export the api call results to a csv with the values of single response in one row?

My api response looks like below
[
{
"What time is it?": [
"option_2"
]
},
{
"When will we go home?": [
"option_1"
]
},
{
"When is your birthday?": [
"2050"
]
},
{
"How much do you sleep?": [
"Ajajajsjiskskskskdkdj"
]
}
],
[
{
"What time is it?": [
"option_2"
]
},
{
"When will we go home?": [
"option_1"
]
},
{
"When is your birthday?": [
"10181"
]
},
{
"How much do you sleep?": [
"Ajskossooskdncpqpqpwkdkdkskkskskksksksksks"
]
}
]
Now in react, I want to export the results to a csv. I can do it by export-to-csv but the formatting is the issue here. I want the values of each question of a single response in one row under their labels(questions). So if I have two response like above I want to have export it in two rows, not 8 as there are 8 total questions.
Here is how I want it to get exported.
I have tried so far like this but no luck.
this is my export data function
exp =()=>{
const raw = []
console.log(this.state.data[0].sbm_id)
axios.get(`/dashboard/${this.props.proj_id}/whole_sub/`)
.then(res=>{
// console.log('1')
// console.log(res.data[0][0])
// console.log('2')
for (let i =0;i<this.state.data.length;i++){
for(let j = 0;j<res.data[0].length;j++){
// let sub=[]
//res.data[i][j].ID = this.state.data[i].sbm_id
raw.push(res.data[i][j])
}
}
}
)
let curr = this.state
curr.exp = raw
this.setState({exp:curr.exp})
}
Here is my export function
rawExport=()=>{
const csvExporter = new ExportToCsv(optionsExp);
csvExporter.generateCsv(this.state.exp);
}
First step is to flatten the initial nested array to get a homogeneously shaped array, then you keep on reducing it further.
const data = [
[
{
"What time is it?": [
"option_2"
]
},
{
"When will we go home?": [
"option_1"
]
},
{
"When is your birthday?": [
"2050"
]
},
{
"How much do you sleep?": [
"Ajajajsjiskskskskdkdj"
]
}
],
[
{
"What time is it?": [
"option_2"
]
},
{
"When will we go home?": [
"option_1"
]
},
{
"When is your birthday?": [
"10181"
]
},
{
"How much do you sleep?": [
"Ajskossooskdncpqpqpwkdkdkskkskskksksksksks"
]
}
]
];
const flattenArray = (arr) => [].concat.apply([], arr);
// Flatten the initial array
const flattenedArray = flattenArray(data);
// Keep on reducing the flattened array into an object
var res = flattenedArray.reduce((acc, curr) => {
const [key, val] = flattenArray(Object.entries(curr));
if (!acc[key]) {
acc[key] = [].concat(val);
} else {
val.forEach(x => {
if (!acc[key].includes(x)) {
acc[key].push(x);
}
});
}
return acc;
}, {});
console.log(res);

Error in vue.js (Multiple root nodes returned from render function)

i'm trying to generate html tags (child nodes) from JSON file with vue.js but i have this Error in console:
(Multiple root nodes returned from render function. Render function should return a single root node)
error screenshot
javaScript Code:
const createComponent = (dNode, h) => {
// Handle empty elements and return empty array in case the dNode passed in is empty
if (_.isEmpty(dNode)) {
return [];
}
// if the el is array call createComponent for all elements
if (_.isArray(dNode)) {
return dNode.map((child) => createComponent(child, h))
}
let children = [];
if (dNode.children && dNode.children.length > 0) {
dNode.children.forEach((c) => {
if (_.isString(c)) {
children.push(c)
} else {
children.push(createComponent(c, h))
}
});
}
// Need to clone
const properties = _.cloneDeep(dNode.properties)
return h(dNode.tagName, properties, children.length > 0? children : dNode.textNode)
}
/**
* A sample component uses the recursive createComponent to render a DOM / List of DOM nodes
*/
const MyComponent = Vue.component('my-component', {
render: function (h) {
return createComponent(this.nodes, h)
},
props: {
nodes: {
type: Array,
required: true
}
}
});
new Vue({
el: "#app",
data: {
nodes: []
},
methods: {
getChildrens() {
this.$http.get('nodes.json').then(response => {
this.nodes = response.body;
}, response => {});
}
},
created() {
this.getShortCodes();
this.getChildrens();
}
});
this is nodes.json File Content
[
{
"tagName": "div",
"children": [
{
"tagName": "h1",
"textNode": "Great News"
},
{
"tagName": "h3",
"textNode": "YOU CAN CREATE VUE COMPONENTS OUT OF JSON"
},
{
"tagName": "a",
"properties": {
"attrs": {"href": "#"}
},
"textNode": "Vue.js"
},
{
"tagName": "h2",
"textNode": "Hello from the other side"
}
]
},
{
"tagName": "div",
"children": [
{
"tagName": "h1",
"textNode": "another title"
},
{
"tagName": "h3",
"textNode": "third item"
},
{
"tagName": "a",
"properties": {
"attrs": {"href": "#"}
},
"textNode": "Vue.js"
},
{
"tagName": "h2",
"textNode": "Hello from the other side"
}
]
}
]
This is the vue.js component which i passed nodes as a props
<div id="app">
<div>
<my-component :nodes="nodes"></my-component>
</div>
</div>
Your createComponent returns an array of VNodes on line 9.
return dNode.map((child) => createComponent(child, h))
It seems that you are always passing an array of node definitions on your component and so you are generating an array of VNodes and Vue doesn't like you to have more than one root element in a component.
You have a couple of ways out of this:
Wrap your array in another element. Something like this:
render: function (h) {
return h('div', {}, createComponent(this.nodes, h))
},
Generate one MyComponent for each top element in your JSON.
You could also change the definition of createComponent to always return a single component, but this could break the semantics of createComponent and you may not have access to that code.
This might be possible with this plugin: https://www.npmjs.com/package/vue-fragments
The plugin let's you do cool stuff like this:
import Fragment from 'vue-fragment'
Vue.use(Fragment.Plugin)
// or
import { Plugin } from 'vue-fragment'
Vue.use(Plugin)
// …
export const MyComponent {
template: '
<fragment>
<input type="text" v-model="message">
<span>{{ message }}</span>
</fragment>
',
data() { return { message: 'hello world }}
}
So the fragment itself won't be in the dom. Hope this helps you out, even though i'm quite late with this answer I see.

Stuck to figure out how to access a certain field to update

I have this JSON FILE
{
"_id": "GgCRguT8Ky8e4zxqF",
"services": {
"emails": [
{
"address": "Abunae#naa.com",
"verified": false,
"verifiedMail": "Toto#hotmail.com"
}
],
"profile": {
"name": "Janis"
},
"pushIds": []
}
I want to update my verifiedMail field but couldn't figure out how to do it in Meteor, it's always returning me an error
let VerifiedEmail = "Exemple1"
await Meteor.users.update({ _id: user._id }, { $set: { 'emails.verifiedEmail': emailRefactor} }, { upsert: true })
Couldn't figure out how to access the emails.verifiedEmail field
Tried this exemlpe worked like a charm
let VerifiedEmail = "Exemple1"
await Meteor.users.update({ _id: user._id }, { $set: { 'profile.name': emailRefactor} }, { upsert: true })
but couldn't figure out how to access emails.verifiedEmail .
Could you please help me ?
Emails is an array, while profile is an object. You have to access the first object of the email array instead
This updates the exact email address from emails
Meteor.users.update({
"emails.address": emailRefactor
}, {
$set: {
"emails.$.verified": true
}
});
Or update the first element
Meteor.users.update({
_id: user._id,
"emails.address": emailRefactor
}, {
$set: {
"emails.0.verified": true
}
});
You're trying to set verifiedEmail while the actual field is verifiedMail.