I'm trying to create entites in Dialogflow using node.js. The entity values will come from a JSON file. I'm currently testing it using postman. However, the entity values are not being separated and being combined in only one line. How do I fix this? Thank you
This is my sample JSON file that is being sent.
{
"Entity_Values": [
{
"Value": "One",
"Synonym":["Solo","1"]},
{
"Value": "Two",
"Synonym":["Double","2"]}
],
"Entity_Name": "Sample"}
This is what I have so far:
function createEntity (inputEntityobj, EntityName) {
const promises = [];
let entity_values = {value:[], synonyms:[]};
let inputEntity_values = [inputEntityobj];
for (i = 0; i < inputEntityobj.length; ++i) {
let inputEntity_values = [inputEntityobj[i].Value];
let inputEntity_synonym = [inputEntityobj[i].Synonym];
entity_values.value.push(inputEntity_values);
entity_values.synonyms.push(inputEntity_synonym);
}
const sizeRequest = {
parent: agentPath,
entityType: {
displayName: (EntityName),
kind: 'KIND_MAP',
autoExpansionMode: 'AUTO_EXPANSION_MODE_UNSPECIFIED',
enableFuzzyExtraction: true,
entities: [entity_values],
},
};
This code outputs
value: [ [ 'One' ], [ 'Two' ] ], synonyms: [ [ [Array] ], [ [Array] ] ]
And in Dialogflow, these are all in one entity entry instead of being in two separate entries.
Your JSON input is almost identical to the required object format for entities (reference) and will only need a little bit of tweaking to make it work. Using your JSON, I renamed the Value and Synonym to value and synonyms. Loop through Entity_values and push the key value pair to list entityVal and use it for the request.
'use strict';
const dialogflow = require('#google-cloud/dialogflow').v2;
var inputEntityObj = {
"Entity_Values": [
{
"Value": "One",
"Synonym":["Solo","1"]},
{
"Value": "Two",
"Synonym":["Double","2"]}
],
"Entity_Name": "Sample"};
var obj = inputEntityObj['Entity_Values'];
// rename keys
var res = obj.map(item => {
item.value= item.Value;
item.synonyms= item.Synonym;
delete item.Value;
delete item.Synonym;
return item;
});
var entityVal =[];
for (const entity in res){
entityVal.push(res[entity]);
}
var projectId = 'your-project-id';
var entityType = { displayName: 'test', //hard coded value for testing purposes
kind: 'KIND_MAP',
autoExpansionMode: 'AUTO_EXPANSION_MODE_UNSPECIFIED',
enableFuzzyExtraction: true,
entities: entityVal,
};
var parent = `projects/${projectId}/agent`;
var request = { parent: parent,
entityType: entityType
};
console.log(JSON.stringify(request, null, 2));
const client = new dialogflow.EntityTypesClient();
client.createEntityType(request);
See testing done below:
request structure:
{
"parent": "projects/your-project-id/agent",
"entityType": {
"displayName": "test",
"kind": "KIND_MAP",
"autoExpansionMode": "AUTO_EXPANSION_MODE_UNSPECIFIED",
"enableFuzzyExtraction": true,
"entities": [
{
"value": "One",
"synonyms": [
"Solo",
"1"
]
},
{
"value": "Two",
"synonyms": [
"Double",
"2"
]
}
]
}
}
Created entity in dialogflow:
Related
I have an object in an array called "Person".
Within the object "Person", there is an array called "info".
My goal is to get all the values with the prefix "age:" in an array "info" when filtering by "gender:male". So, my desired output will be 1 to 9 because I want also to remove duplicates.
Below is my code but the results are only two values (1 and 4). Maybe the output is one value per person.
I spent a lot of hours playing the code but no luck. That's why I bring my problem here hoping anybody who is an expert on this can help me.
<script>
var array = [
{
"person": {
"info": [
"age:1",
"age:2",
"age:3",
"age:4",
"age:5",
"age:6",
"gender:male"
]
},
"person": {
"info": [
"age:4",
"age:5",
"age:6",
"age:7",
"age:8",
"age:9",
"gender:male"
]
},
"person": {
"info": [
"age:8",
"age:9",
"age:10",
"age:11",
"age:12",
"age:13",
"gender:female"
]
}
}
]
var filteredAges = [];
for (i = 0; i < array.length; i++) {
var infoGroup = array[i].person.info,
ageGroup = [];
for (j = 0; j < infoGroup.length; j++) {
ageGroup.push(infoGroup[j]);
var ageInfo = ageGroup.find(ages => ages.includes('age:'));
};
if (ageInfo) {
if (filteredAges.indexOf(ageInfo) == -1) {
filteredAges.push(ageInfo)
}
}
}
for (i = 0;i < filteredAges.length; i++) {
console.log(filteredAges[i]);
}
</script>
Seems like all your object keys are just person i.e
[
{
person: {...},
person: {...},
person: {...}
}
]
So when the variable array is evaluated it just has one person
You need to restructure your data maybe like below or something similar
Example - 1
[
{ person: {...} },
{ person: {...} },
{ person: {...} },
]
Example - 2
[
[ { person: {...} } ],
[ { person: {...} } ],
[ { person: {...} } ]
]
After fixing this you can try debugging your problem
If you want to get all items in info array that has "age:"
you can use filter like this
const ageInfos = [
"age:8", "age:9",
"age:10", "age:11",
"age:12", "age:13",
"gender:female"
].filter(x => x.startsWith("age:"))
Your output - ageInfos will be
["age:8", "age:9", "age:10", "age:11", "age:12", "age:13"]
You can also use Set to only collect unique strings or just push everything to an array and later use Set to return only unique values like this
const arrayWithDuplicates = ['a', 1, 'a', 2, '1'];
const unique = [...new Set(arrayWithDuplicates)];
console.log(unique); // unique is ['a', 1, 2, '1']
First of all, your JSON is wrong. You just overright person object.
Data structure is really awful, I would recommend you to rethink it.
Assuming person will not be overwritten I came up with this solution.
var array = [
{
"person": {
"info": [
"age:1",
"age:2",
"age:3",
"age:4",
"age:5",
"age:6",
"gender:male"
]
},
"person1": {
"info": [
"age:4",
"age:5",
"age:6",
"age:7",
"age:8",
"age:9",
"gender:male"
]
},
"person2": {
"info": [
"age:8",
"age:9",
"age:10",
"age:11",
"age:12",
"age:13",
"gender:female"
]
}
}
]
let agesArray = []
let ages = []
array.forEach((peopleObj) => {
for (const index in peopleObj) {
ages = peopleObj[index].info.map((age) => {
const ageNumber = age.split(':')[1]
if (parseInt(ageNumber)) {
return ageNumber
}
}).filter(val => !!val)
agesArray = [...agesArray, ...ages]
}
})
Thanks a lot guys. I'll apply all of your ideas and try if it can solve my problem.
This is Browser localstorage Object referred as dataset
let dataset = localStorage.getItem('dataset') !== null ? leech : [];
[
{
"id": 123,
"name": "abc"
},
{
"id": 456,
"name": "bcd"
}
]
This is the initial data object available I want to add more field to a particular id.
This is what I want :
[
{
"id": 123,
"name": "abc"
},
{
"id": 456,
"name": "bcd",
"status":1
}
]
This my code to find the particular id
const user = dataset.find(user => user.id == 456);
Now how can I add status to user and update the user in the dataset?
You've already found the user by using Array.prototype.find() so all you need to do then is add the status property
// const dataset = JSON.parse(localStorage.getItem("dataset"))
const dataset = [{"id":123,"name":"abc"},{"id":456,"name":"bcd"}]
const user = dataset.find(({ id }) => id === 456)
if (user) {
user.status = 1
}
console.info(dataset)
.as-console-wrapper { max-height: 100% !important }
If you then want to store the modified data back into localStorage, use localStorage.setItem() and JSON.stringify()
localStorage.setItem("dataset", JSON.stringify(dataset))
If you want keep dataset initial value, and would like to get a new array, you can use Array.reduce() method.
const dataset = [
{
"id": 123,
"name": "abc"
},
{
"id": 456,
"name": "bcd"
}
]
const output = dataset.reduce((acc, cur) => {
if (cur.id === 456) cur.status = 1;
acc.push(cur);
return acc;
}, []);
console.log(output);
If you want to update dataset, you can use Array.forEach() method.
const dataset = [
{
"id": 123,
"name": "abc"
},
{
"id": 456,
"name": "bcd"
}
]
dataset.forEach(user => {
if (user.id === 456) user.status = 1;
});
console.log(dataset);
You could do with Array#Findindex with callback return function. so could pass the originaldata,searchId and update object. In this method you could updated object easily
Why i suggest findIndex
Because findindex not running entire loop or iteration. If the match
detect on first iteration they will break the loop and returning the
result.For long iteration its more faster than other loop (reduce,forEach)
const data = [ { "id": 123, "name": "abc" }, { "id": 456, "name": "bcd" } ]
function update(dataset,searchId,addtionObject){
let ind = dataset.findIndex(({id}) => id == searchId);
dataset[ind] = {...dataset[ind],...addtionObject}; //join the new and old array
return dataset
}
console.log(update(data,456,{status:1}))
If you want to create new state objet, you can use immer for that.
Immer will produce the nextState based on the mutations to the draft state.
import produce from "immer";
const baseState = [
{
id: 123,
name: "abc",
},
{
id: 456,
name: "bcd",
},
];
const nextState = produce(baseState, (draftState) => {
draftState[1].status = 1;
});
Here is my code :
var obj2 = [{
"name": "4134",
"calls": [
]
}]
var obj3 = [{ Channel: 'SIP/4134-0004462a',
Accountcode: '7013658596'},
{ Channel: 'DAHDI-il-4134-sa',
Accountcode: '07717754702',
}]
var func = (obj2, obj3) => {
obj2.forEach((a) =>
obj3.forEach((b) => {
if (b.Channel.includes(a.name)) a.calls = (a.calls || []).concat(Object.assign({}, { MobileNo: b.Accountcode}));
})
);
};
func(obj2, obj3);
console.log(JSON.stringify(obj2));
Link to my JS-Fiddle
Here is my current output:
[
{
"name": "4134",
"calls": [
{
"MobileNo": "7013658596"
},
{
"MobileNo": "07717754702"
}
]
}
]
In the above code I have two objects. In obj2 the value of the name key is 4134. In my code I'm checking if this 4134 exists in the value of the Channel key in obj3 by using if (b.Channel.includes(a.name)). I have used the includes function here. So if 4134 exists in the value of Channel in obj3 then the Accountcode is pushed into the calls array of obj2 when there's a match. As you can see one of Channel is SIP/4134-0004462a and the other one is DAHDI-il-4134-sa. Both of them contain 4134 but I only want to compare the values where the Channel contains the text SIP in it. As you can see in the above output that the Accountcode from both the objects in obj3 are pushed to calls array in obj2 as both the Channels contain 4134. This is not what I want.
Here is the desired output that I want :
[
{
"name": "4134",
"calls": [
{
"MobileNo": "7013658596"
}
]
}
]
In the above-desired output, 4134 is matched only with the Channel containing the text SIP in it.
How do I do it using the includes function?
Change if (b.Channel.includes(a.name))...
to
if(b.Channel.includes(a.name) && b.Channel.match('SIP'))...
I solved the problem by using one more condition in the if statement like this
if (b.Channel.includes('SIP') && b.Channel.includes(a.name))
Final Code
var obj2 = [{
"name": "4134",
"calls": [
]
}]
var obj3 = [{ Channel: 'SIP/4134-0004462a',
Accountcode: '7013658596'},
{ Channel: 'DAHDI-il-4134-sa',
Accountcode: '07717754702',
}]
var func = (obj2, obj3) => {
obj2.forEach((a) =>
obj3.forEach((b) => {
if (b.Channel.includes('SIP') && b.Channel.includes(a.name)) a.calls = (a.calls || []).concat(Object.assign({}, { MobileNo: b.Accountcode}));
})
);
};
func(obj2, obj3);
console.log(JSON.stringify(obj2));
Now I'm getting the desired output as well.
[
{
"name": "4134",
"calls": [
{
"MobileNo": "7013658596"
}
]
}
]
Thank you community for giving your time.
I found the question How to convert a file path into treeview?, but I'm not sure how to get the desired result in JavaScript:
I'm trying to turn an array of paths into a JSON tree:
var paths = [
"/org/openbmc/UserManager/Group",
"/org/stackExchange/StackOverflow",
"/org/stackExchange/StackOverflow/Meta",
"/org/stackExchange/Programmers",
"/org/stackExchange/Philosophy",
"/org/stackExchange/Religion/Christianity",
"/org/openbmc/records/events",
"/org/stackExchange/Religion/Hinduism",
"/org/openbmc/HostServices",
"/org/openbmc/UserManager/Users",
"/org/openbmc/records/transactions",
"/org/stackExchange/Religion/Islam",
"/org/openbmc/UserManager/Groups",
"/org/openbmc/NetworkManager/Interface"
];
I want to have json structure like below using the folder paths.
var xyz = [{
"path": "photos",
"name": "photos",
"children": [
{
"path": "photos/summer",
"name": "summer",
"children": [
{
"path": "photos/summer/june",
"name": "june",
"children": [
{
"path": "photos/summer/june/windsurf",
"name": "windsurf",
}
]
}
]
},
{
"path": "photos/winter",
"name": "winter",
"children": [
{
"path": "photos/winter/january",
"name": "january",
"children": [
{
"path": "photos/winter/january/ski",
"name": "ski",
},
{
"path": "photos/winter/january/snowboard",
"name": "snowboard",
}
]
}
]
}
]
}];
I have used below function but it's not working
var parsePathArray = function(paths) {
var parsed = [];
for (var i = 0; i < paths.length; i++) {
var position = parsed;
var split = paths[i].split('/');
for (var j = 0; j < split.length; j++) {
if (split[j] !== "") {
if (typeof position[split[j]] === 'undefined')
position[split[j]] = {};
position.children = [position[split[j]]];
position.name = split[j];
position = position[split[j]];
}
}
}
return parsed;
}
Disclaimer: I wrote this answer because it's a fun exercise. I'm still disappointed in you for not trying and not taking the time to explain what it is you don't understand...
I didn't follow your exact format so you'll have to try to understand how it's done instead of being able to copy the code and leave :)
I'll touch upon each step briefly to not risk explaining what you already know.
Step 1:
Go from a list of strings to a list of arrays:
["a/1", "a/2", "b/1"] -> [["a", "1"], ["a", "2"], ["b", "1"]]
We use String.prototype.slice to remove the prepended "/" and String.prototype.split with your folder delimiter to convert to an array: path.split("/")
Step 2
Loop over each folder and add the folder to an object.
[["a", "1"], ["a", "2"], ["b", "1"]] -> { a: { 1: {}, 2: {} }, b: { 1: {} } }
We use a reducer that accesses an object using bracket notation obj[key] instantiating new folder objects and returning the deepest location along the way.
Step 3
Recursively loop over the keys of your object and convert to a specified format:
{ a: { 1: { } } -> { name: "a", path: [], children: [ /* ... */ ] }
We take a list of keys, which are folder names, using Object.keys. Recursively call for each nested object.
Please, update your answer with the specific step you have trouble with which allows others to help as well, and me to describe the step in more detail.
const pathStrings = ["/org/openbmc/UserManager/Group", "/org/stackExchange/StackOverflow", "/org/stackExchange/StackOverflow/Meta", "/org/stackExchange/Programmers", "/org/stackExchange/Philosophy", "/org/stackExchange/Religion/Christianity", "/org/openbmc/records/events", "/org/stackExchange/Religion/Hinduism", "/org/openbmc/HostServices", "/org/openbmc/UserManager/Users", "/org/openbmc/records/transactions", "/org/stackExchange/Religion/Islam", "/org/openbmc/UserManager/Groups", "/org/openbmc/NetworkManager/Interface"];
const paths = pathStrings
.map(str => str.slice(1)) // remove first "/"
.map(str => str.split("/"));
// Mutates map!
const mergePathInToMap = (map, path) => {
path.reduce(
(loc, folder) => (loc[folder] = loc[folder] || {}, loc[folder]),
map
);
return map;
};
// Folder structure as { folderName: folderContents }
const folderMap = paths.reduce(mergePathInToMap, {});
// Go from
// { folderName: folderContents }
// to a desired format like
// { name: folderName, children: [contents] }
const formatStructure = (folder, path) => {
return Object
.keys(folder)
.map(k => ({
name: k,
path: path,
children: formatStructure(folder[k], path.concat(k))
}))
}
console.log(
JSON.stringify(
formatStructure(folderMap, []),
null,
2
)
)
.as-console-wrapper { min-height: 100% }
I have data that's in this format:
{
"columns": [
{
"values": [
{
"data": [
"Project Name",
"Owner",
"Creation Date",
"Completed Tasks"
]
}
]
}
],
"rows": [
{
"values": [
{
"data": [
"My Project 1",
"Franklin",
"7/1/2015",
"387"
]
}
]
},
{
"values": [
{
"data": [
"My Project 2",
"Beth",
"7/12/2015",
"402"
]
}
]
}
]
}
Is there some super short/easy way I can format it like so:
{
"projects": [
{
"projectName": "My Project 1",
"owner": "Franklin",
"creationDate": "7/1/2015",
"completedTasks": "387"
},
{
"projectName": "My Project 2",
"owner": "Beth",
"creationDate": "7/12/2015",
"completedTasks": "402"
}
]
}
I've already got the column name translation code:
r = s.replace(/\%/g, 'Perc')
.replace(/^[0-9A-Z]/g, function (x) {
return x.toLowerCase();
}).replace(/[\(\)\s]/g, '');
Before I dive into this with a bunch of forEach loops, I was wondering if there was a super quick way to transform this. I'm open to using libraries such as Underscore.
function translate(str) {
return str.replace(/\%/g, 'Perc')
.replace(/^[0-9A-Z]/g, function (x) {
return x.toLowerCase();
})
.replace(/[\(\)\s]/g, '');
}
function newFormat(obj) {
// grab the column names
var colNames = obj.columns[0].values[0].data;
// create a new temporary array
var out = [];
var rows = obj.rows;
// loop over the rows
rows.forEach(function (row) {
var record = row.values[0].data;
// create a new object, loop over the existing array elements
// and add them to the object using the column names as keys
var newRec = {};
for (var i = 0, l = record.length; i < l; i++) {
newRec[translate(colNames[i])] = record[i];
}
// push the new object to the array
out.push(newRec);
});
// return the final object
return { projects: out };
}
DEMO
There is no easy way, and this is really not that complex of an operation, even using for loops. I don't know why you would want to use regex to do this.
I would start with reading out the column values into a numerically indexed array.
So something like:
var sourceData = JSON.parse(yourJSONstring);
var columns = sourceData.columns[0].values[0].data;
Now you have a convenient way to start building your desired object. You can use the columns array created above to provide property key labels in your final object.
var sourceRows = sourceData.rows;
var finalData = {
"projects": []
};
// iterate through rows and write to object
for (i = 0; i < sourceRows.length; i++) {
var sourceRow = sourceRows[i].values.data;
// load data from row in finalData object
for (j = 0; j < sourceRow.length; j++) {
finalData.projects[i][columns[j]] = sourceRow[j];
}
}
That should do the trick for you.