Related
I am building a drag and drop application -- that is given a multidimensional array of supported file type and titles for those file types and icons to use against them in a legend. The drag and drop picks up an accept array that has specific mime types -- I need to display to the user in easy terms what file types are allowed -- so return a comma delimited string - jpg, pdf
what is the best way of looping through the multidimensional array to get at the key in the forms to complete this task?
getAcceptedFileTypes(){
let supportedFiles = [{
"images": {
"icon": <ImageIcon />,
"formats": [{"png": "image/png"}, {"jpeg": "image/jpeg"}],
}
},{
"compressed_files": {
"icon": <DescriptionIcon />,
"formats": [{"zip": "application/x-zip-compressed"}, {"rar": "application/x-rar-compressed"}],
}
},{
"documents": {
"icon": <FileCopyIcon />,
"formats": [{"pdf": "application/pdf"}, {"docx": "application/msword"}, {"doc": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}],
}
}];
let accept = ["application/pdf","image/jpeg"]
console.log("supportedFiles", supportedFiles);
console.log("accept", accept);
let acceptedFiles = "jpeg, pdf";
return (
acceptedFiles
)
}
You could do something like:
let supportedFiles = [{
"images": {
"icon": "<ImageIcon />",
"formats": [{
"png": "image/png"
}, {
"jpeg": "image/jpeg"
}],
}
}, {
"compressed_files": {
"icon": "<DescriptionIcon />",
"formats": [{
"zip": "application/x-zip-compressed"
}, {
"rar": "application/x-rar-compressed"
}],
}
}, {
"documents": {
"icon": "<FileCopyIcon />",
"formats": [{
"pdf": "application/pdf"
}, {
"docx": "application/msword"
}, {
"doc": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
}],
}
}];
let accept = ["application/pdf", "image/jpeg"];
const acceptedFiles = supportedFiles.reduce((acc, item) => {
const subItem = Object.values(item)[0];
subItem.formats.forEach((format, index) => {
if (accept.indexOf(Object.values(format)[0]) > -1) {
acc.push(Object.keys(subItem.formats[index])[0]);
}
});
return acc;
}, []).join(', ');
//test
console.log(acceptedFiles);
You mean this?
const getAcceptedFileTypes = () => {
let supportedFiles = [{
"images": {
"icon": `<ImageIcon />`,
"formats": [{
"png": "image/png"
}, {
"jpeg": "image/jpeg"
}],
}
}, {
"compressed_files": {
"icon": `<DescriptionIcon />`,
"formats": [{
"zip": "application/x-zip-compressed"
}, {
"rar": "application/x-rar-compressed"
}],
}
}, {
"documents": {
"icon": `<FileCopyIcon />`,
"formats": [{
"pdf": "application/pdf"
}, {
"docx": "application/msword"
}, {
"doc": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
}],
}
}];
let acceptedFiles = supportedFiles.flatMap(file => file[Object.keys(file)[0]].formats)
return (
acceptedFiles
)
}
console.log(getAcceptedFileTypes())
console.log(getAcceptedFileTypes().map(entry => Object.keys(entry)[0]).join(","))
Might wanna try this
let supportedFiles = [{
"images": {
"icon": '<ImageIcon />',
"formats": [{"png": "image/png"}, {"jpeg": "image/jpeg"}],
}
},{
"compressed_files": {
"icon": '<DescriptionIcon />',
"formats": [{"zip": "application/x-zip-compressed"}, {"rar": "application/x-rar-compressed"}],
}
},{
"documents": {
"icon": '<FileCopyIcon />',
"formats": [{"pdf": "application/pdf"}, {"docx": "application/msword"}, {"doc": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}],
}
}];
let acceptedFiles=[];
supportedFiles.forEach((fileType)=>{
Object.keys(fileType).forEach(key=>{
fileType[key].formats.forEach(format=>{
acceptedFiles.push(Object.keys(format));
})
})
})
console.log(acceptedFiles.join(","))
If you change the structure then:
let supportedFilesObj ={
"images": {
"icon": '<ImageIcon />',
"formats": [{"png": "image/png"}, {"jpeg": "image/jpeg"}],
},
"compressed_files": {
"icon": '<DescriptionIcon />',
"formats": [{"zip": "application/x-zip-compressed"}, {"rar": "application/x-rar-compressed"}],
},
"documents": {
"icon": '<FileCopyIcon />',
"formats": [{"pdf": "application/pdf"}, {"docx": "application/msword"}, {"doc": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}],
}
};
let acceptedFiles=[];
Object.keys(supportedFilesObj).forEach((key)=>{
supportedFilesObj[key].formats.forEach(format=>{
acceptedFiles.push(Object.keys(format));
})
})
console.log(acceptedFiles.join(","))
Here is a simple solution using 3 nested for loops.
function getAcceptedFileExtensions() {
let acceptedExtensions = [];
for (let fileTypeObject of supportedFiles) {
for (let fileTypeKey of Object.keys(fileTypeObject)) {
for (let extensionPair of fileTypeObject[fileTypeKey].formats) {
acceptedExtensions.push(Object.keys(extensionPair)[0]);
}
}
}
return acceptedExtensions;
}
console.log(getAcceptedFileExtensions().toString());
The data structure is a bit weird as it contains an array of objects containing one key, which seems to be the name of each object, instead of e.g. an object with the different file-type-categories directly. Because of that the second loop could be shortened to Object.keys(fileTypeObject)[0]:
const supportedFiles = [
{
"images": {
"icon": "<ImageIcon />",
"formats": [
{ "png": "image/png" },
{ "jpeg": "image/jpeg" }
],
}
},
{
"compressed_files": {
"icon": "<DescriptionIcon />",
"formats": [
{ "zip": "application/x-zip-compressed" },
{ "rar": "application/x-rar-compressed" }
],
}
},
{
"documents": {
"icon": "<FileCopyIcon />",
"formats": [
{ "pdf": "application/pdf" },
{ "docx": "application/msword" },
{ "doc": "application/vnd.openxmlformats-officedocument.wordprocessingml.document" }
],
}
}
];
function getAcceptedFileExtensions() {
let acceptedExtensions = [];
for (let fileTypeObject of supportedFiles) {
let fileTypeKey = Object.keys(fileTypeObject)[0];
for (let extensionPair of fileTypeObject[fileTypeKey].formats) {
acceptedExtensions.push(Object.keys(extensionPair)[0]);
}
}
return acceptedExtensions;
}
console.log(getAcceptedFileExtensions().toString());
If this is an recurring operation, you can create a mapper object which maps each MIME type to its file extension name
const mapper = {}
for (const file of supportedFiles) {
const { formats } = Object.values(file)[0]
for (const format of formats) {
const [key, value] = Object.entries(format)[0]
mapper[value] = key;
}
}
function getAcceptedFiles(accept, mapper) {
return accept.map(t => mapper[t])
}
Mapper object:
{
"image/png": "png",
"image/jpeg": "jpeg",
"application/x-zip-compressed": "zip",
"application/x-rar-compressed": "rar",
"application/pdf": "pdf",
"application/msword": "docx",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "doc"
}
Here's a snippet:
const supportedFiles=[{images:{icon:"",formats:[{png:"image/png"},{jpeg:"image/jpeg"}],}},{compressed_files:{icon:"",formats:[{zip:"application/x-zip-compressed"},{rar:"application/x-rar-compressed"}],}},{documents:{icon:"",formats:[{pdf:"application/pdf"},{docx:"application/msword"},{doc:"application/vnd.openxmlformats-officedocument.wordprocessingml.document"}],}}];
const mapper = {}
for (const file of supportedFiles) {
const { formats } = Object.values(file)[0]
for (const format of formats) {
const [key, value] = Object.entries(format)[0]
mapper[value] = key;
}
}
function getAcceptedTypes(accept, mapper) {
return accept.map(t => mapper[t])
}
console.log( getAcceptedTypes( ["application/pdf","image/jpeg"], mapper) )
console.log( getAcceptedTypes( ["application/x-rar-compressed"], mapper) )
I have a json object array I have two functions. One to get the last message and the other to get. I need to keep the outer format the same but only return the one message.
I am getting the Json from the Telegram api and I have a Node Express script to return the reformatted Json
Here is the full Json:
{
"ok": true,
"result": [
{
"update_id": 650787950,
"channel_post": {
"message_id": 258,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256395,
"text": "test messge"
}
},
{
"update_id": 650787951,
"channel_post": {
"message_id": 259,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256604,
"text": "next"
}
}
]
}
I have a function to store the object after an api call to Telegram:
storeUpdates(data){
this.messageData = data;
}
For the function to get the last message:
getlastMessage() {
return
}
I am trying to return the Json:
{
"ok": true,
"result": [
{
"update_id": 650787951,
"channel_post": {
"message_id": 259,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256604,
"text": "next"
}
}
]
}
And for the function to get a specific update_id
getNextMessage(update_id) {
return
}
Again I am trying to get this format of a single message matching the passed in update_id
{
"ok": true,
"result": [
{
"update_id": 650787951,
"channel_post": {
"message_id": 259,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256604,
"text": "next"
}
}
]
}
I am a little confused with the layers of object and arrays mixed.
Does this work?
const messages = {
ok: true,
result: [{
update_id: 650787950,
channel_post: {
message_id: 258,
chat: {
id: -1001497153100,
title: 'TestBot',
type: 'channel',
},
date: 1592256395,
text: 'test messge',
},
},
{
update_id: 650787951,
channel_post: {
message_id: 259,
chat: {
id: -1001497153100,
title: 'TestBot',
type: 'channel',
},
date: 1592256604,
text: 'next',
},
},
],
};
const getLastMessage = (messages) => {
final = {
ok: true,
result: [],
};
final.result.push(messages.result[messages.result.length - 1]);
return final;
};
const getNextMessage = (update_id, messages) => {
final = {
ok: true
};
final.result = messages.result.filter((msg) => {
return msg.update_id === update_id;
});
return final;
};
console.log(getLastMessage(messages));
console.log(getNextMessage(650787950, messages));
You get the last message by returning the last element in the array, by getting the length of the array and -1
I used Array.prototype.filter() to find the correct object.
To get the last result you would need to go to results and return the last index:
function getlastMessage(resultObject) {
return {
ok: resultObject.ok
result: [resultObject.result[resultObject.result.length - 1]]
}
}
To get the message by update_id:
getNextMessage(update_id) {
return {
ok: resultObject.ok
result: [resultObject.result.find(message => message.update_id === update_id)]
}
}
Something along these lines
Using destructuring you can make your code a little bit more compact:
const someObject = JSON.parse(`{
"ok": true,
"result": [
{
"update_id": 650787950,
"channel_post": {
"message_id": 258,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256395,
"text": "test messge"
}
},
{
"update_id": 650787951,
"channel_post": {
"message_id": 259,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256604,
"text": "next"
}
}
]
}`)
const getNextMessage = (update_id) => {
return {
...someObject,
result: someObject.result.find(message => message.update_id === update_id)
}
}
const getLastMessage = () => {
const arrayLength = someObject.result.length;
return {
...someObject,
result: someObject.result[arrayLength - 1]
}
}
console.log(getNextMessage(650787950))
console.log(getLastMessage())
If you want to keep the result type as an array you can use filter instead of find and surround the last element of result array with square brackets, like this:
const getNextMessage = (update_id) => {
return {
...someObject,
result: someObject.result.filter(message => message.update_id === update_id)
}
}
const getLastMessage = () => {
const arrayLength = someObject.result.length;
return {
...someObject,
result: [someObject.result[arrayLength - 1]]
}
}
i have a nested array of object and i want to convert in arraylist like this :
this is my data array of object :
{
"status": true,
"message": "",
"data": [{
"pasien_docs": [{
"ecg": null,
"date": "2020-01-21T05:22:01.901Z"
}, {
"ecg": 1.03,
"date": "2020-01-21T05:22:02.979Z"
}, {
"ecg": 1.04,
"date": "2020-01-21T05:22:04.053Z"
}, {
"ecg": 1.04,
"date": "2020-01-21T05:22:05.126Z"
},
]
}
]
}
and i want change convert to array like this :
{
"status": true,
"message": "",
"data": [
[
"2020-01-21T05:22:01.901Z",
null
],
[
"2020-01-21T05:22:01.901Z",
1, 03
]
[
"2020-01-21T05:22:01.901Z",
1.04
]
[
"2020-01-21T05:22:01.901Z",
1.04
]
]
}
i try using map to convert on result like this :
result = result.map((u, i) => [
u.pasien_docs[i].date,
u.pasien_docs[i].ecg,
]);
but why i only get result data of one array not four data ? help me please, thankyou..
{
"status": true,
"message": "",
"data": [
[
"2020-01-21T05:22:01.901Z",
null
]
]
}
Would that work for you?
const src = {"status":true,"message":"","data":[{"pasien_docs":[{"ecg":null,"date":"2020-01-21T05:22:01.901Z"},{"ecg":1.03,"date":"2020-01-21T05:22:02.979Z"},{"ecg":1.04,"date":"2020-01-21T05:22:04.053Z"},{"ecg":1.04,"date":"2020-01-21T05:22:05.126Z"},]}]},
result = {
...src,
data: src.data[0].pasien_docs.map(Object.values)
}
console.log(result)
.as-console-wrapper{min-height:100%;}
If you dont wanna use spread operator, this can also do the trick for you
const source = {"status":true,"message":"","data":[{"pasien_docs":[{"ecg":null,"date":"2020-01-21T05:22:01.901Z"},{"ecg":1.03,"date":"2020-01-21T05:22:02.979Z"},{"ecg":1.04,"date":"2020-01-21T05:22:04.053Z"},{"ecg":1.04,"date":"2020-01-21T05:22:05.126Z"},]}]}
const result = Object.assign({}, source, {
data: source.data[0].pasien_docs.map(Object.values)
})
console.log(result)
let obj = {
status: true,
message: "",
data: [
{
pasien_docs: [
{
ecg: null,
date: "2020-01-21T05:22:01.901Z",
},
{
ecg: 1.03,
date: "2020-01-21T05:22:02.979Z",
},
{
ecg: 1.04,
date: "2020-01-21T05:22:04.053Z",
},
{
ecg: 1.04,
date: "2020-01-21T05:22:05.126Z",
},
],
},
],
};
var finalobj = JSON.parse(JSON.stringify(obj));
var innerobj = obj.data;
var intermd = innerobj.map((data) => {
return data.pasien_docs;
});
finalarray = intermd[0].map((val) => {
return [val.ecg, val.date];
});
console.log(obj);
finalobj.data[0].pasien_docs=finalarray;
console.log(finalobj);
I have a collection in MongoDB like this
[
{
"classId": "1",
"name": "Input",
"definition": [
{
"property": [
{
"classId": "12",
"name": "One"
},
{
"classId": "8",
"name": "Comment"
}
]
}
]
},
{
"classId": "8",
"name": "CommentDetail",
"definition": [
{
"property": [
{
"classId": "10",
"name": "user"
},
{
"classId": "10",
"name": "message"
}
]
}
]
},
{
"classId": "10",
"name": "String",
"definition": []
},
{
"classId": "12",
"name": "Int",
"definition": []
}
]
Based on db above, I have a model to display
data = {
name:'',
template: ''
}
With classId=1, the expectation result is
{
"Name": "Input",
"temlate": "{['One': 'Int','Comment': ['user': 'String','message':'String']]}"
}
I try to using recursive promise to implement it. When property[] is empty, the result will be return.
Here is my function:
const getObjectTypeByClassId = (snapshotId, artifactId, objectType) => {
return artifactDetailModel.find({
'snapshotId': snapshotId,
'artifactId': artifactId
})
.then(data => {
let artifact = data[0];
let definition;
let definitionData = {};
return Promise.resolve()
.then(() => {
definition = artifact.data.teamworks.twClass[0].definition[0];
if (!lodash.isUndefined(definition.property)) {
const listOfProperty = definition.property;
for (let property of listOfProperty) {
classId = commonUtil.getArtifactId(property.classRef[0]);
if (!lodash.isUndefined(classId)) {
return getObjectTypeByClassId(snapshotId, classId, objectType);
}
}
} else {
definitionData.nameType = artifact.data.teamworks.twClass[0].elementAttribute.name;
definitionData.classId = artifact.data.teamworks.twClass[0].elementAttribute.id;
definitionData.template = bpmMapping.objectType[artifact.data.teamworks.twClass[0].elementAttribute.name];
return objectTypeModel.create(definitionData)
.then(obj => {
const response = {
name: objectType.name,
isArrayOf: objectType.isArrayOf,
nameType: obj.nameType,
template: obj.template,
}
return response;
})
}
})
})
}
Run with my function, the response is
data: {
Name: Input
temlate: user: String,
}
Please advice me.
I tried it to some extent, but wasn't able to get it right. Plus your expected output is not the valid JSON "temlate": {[]} doesn't make sense.
It has nothing to do with Promise. You have to DFS you db array and created expected output. Here is what I have donup tillll now, you can think along those lines. But this is far from the solution.
let mainArray = [
{
"classId": "1",
"name": "Input",
"definition": [
{
"property": [
{
"classId": "12",
"name": "One"
},
{
"classId": "8",
"name": "Comment"
}
]
}
]
},
{
"classId": "8",
"name": "CommentDetail",
"definition": [
{
"property": [
{
"classId": "10",
"name": "user"
},
{
"classId": "10",
"name": "message"
}
]
}
]
},
{
"classId": "10",
"name": "String",
"definition": []
},
{
"classId": "12",
"name": "Int",
"definition": []
}
]
function dfs(root, createdRoot, fn, level) {
fn(root,createdRoot, level);
if(root.definition)/*if definition exists => keep traversing*/
root.definition[0].property.forEach(function (child) {
createdRoot.template = createdRoot.template || [];
let tempObj = {};
let lookupObj = lookupByClassId(child.classId);
tempObj[child.name] = lookupObj.name;
createdRoot.template.push(tempObj);
dfs(child,tempObj, fn, level + 1);
});
else /*if definition doesn't exist, look into the array*/
{
createdRoot.template = lookupByClassId(root.classId);
}
}
function lookupByClassId(classId){
for(let i=0;i<mainArray.length;++i){
let element =mainArray[i]
if(element.classId == classId)
return element;
}
}
let root = lookupByClassId(1);
createdRoot ={};
function func1(root, createdRoot, level) {
createdRoot.name = root.name;
console.log(root.classId);
}
dfs(root, createdRoot, func1, 0);
here is the solution from a guy on the internet. it works well. Thanks, #Cuong Quach
var MongoClient = require('mongodb').MongoClient;
var database = 'testdequy';
var collection = 'classes';
MongoClient.connect("mongodb://localhost:27017/" + database, function (err, db) {
findDetails("1").then((r) => {
console.log("r>>>", r);
})
function findDetails(classId) {
var results = { Name: "", Template: "" };
var template = {};
return new Promise((main_resolve, reject) => {
process(template, "" , classId)
var works = 0;
function process(parent, childKey, objectId) {
return new Promise((resolve, reject) => {
db.collection(collection).find({ classId: objectId })
.toArray((err, docs) => {
if (results.Name == "") {
results.Name = docs[0].name;
}
let objectItem;
if (childKey == "")
objectItem = parent;
else
objectItem = parent[childKey];
console.log("\ndocs", docs[0], objectId, objectItem)
if (docs[0].definition.length == 0 || docs[0].definition[0].property == undefined) {
let name = docs[0].name;
parent[childKey] = name;
console.log("\nNo child", docs[0],parent, objectItem, docs[0].name)
resolve(0);
} else {
docs[0].definition[0].property.forEach((item) => {
works++;
//console.log("item", item)
let id = item.classId;
let name = item.name;
objectItem[name] = {};
process(objectItem, name, id).then((len)=>{
works--;
if(len == 0 && works == 0) main_resolve(template);
})
})
resolve(docs[0].definition[0].property.length)
}
})
})
}
})
}
});
I have an array with objects, like the following.
b = {
"issues": [{
"fields": {
"status": {
"id": "200",
"name": "Backlog"
}
}
}, {
"fields": {
"status": {
"id": "202",
"name": "close"
}
}
}, {
"fields": {
"status": {
"id": "201",
"name": "close"
}
}
}]
};
I want to count how many issues have status close, and how many have backlog. I'd like to save the count in a new array as follows.
a = [
{Name: 'Backlog', count: 1},
{Name: 'close', count: 2}
];
I have tried the following.
b.issues.forEach(function(i) {
var statusName = i.fields.status.name;
if (statusName in a.Name) {
a.count = +1;
} else {
a.push({
Name: statusName,
count: 1
});
}
});
That however doesn't seem to be working. How should I implement this?
This is a perfect opportunity to use Array#reduce. That function will take a function that is applied to all elements of the array in order and can be used to accumulate a value. We can use it to accumulate an object with the various counts in it.
To make things easy, we track the counts in an object as simply {name: count, otherName: otherCount}. For every element, we check if we already have an entry for name. If not, create one with count 0. Otherwise, increment the count. After the reduce, we can map the array of keys, stored as keys of the object, to be in the format described in the question. See below.
var b = {
"issues": [{
"fields": {
"status": {
"id": "200",
"name": "Backlog"
}
}
}, {
"fields": {
"status": {
"id": "202",
"name": "close"
}
}
}, {
"fields": {
"status": {
"id": "201",
"name": "close"
}
}
}]
};
var counts = b.issues.reduce((p, c) => {
var name = c.fields.status.name;
if (!p.hasOwnProperty(name)) {
p[name] = 0;
}
p[name]++;
return p;
}, {});
console.log(counts);
var countsExtended = Object.keys(counts).map(k => {
return {name: k, count: counts[k]}; });
console.log(countsExtended);
.as-console-wrapper {
max-height: 100% !important;
}
Notes.
Array#reduce does not modify the original array.
You can easily modify the function passed to reduce to for example not distinguish between Backlog and backlog by changing
var name = c.fields.status.name;
into
var name = c.fields.status.name.toLowerCase();
for example. More advanced functionality can also easily be implemented.
Using ES6 Arrow functions you can do it with minimum syntax
var b = {
"issues": [{
"fields": {
"status": {
"id": "200",
"name": "Backlog"
}
}
}, {
"fields": {
"status": {
"id": "202",
"name": "close"
}
}
}, {
"fields": {
"status": {
"id": "201",
"name": "close"
}
}
}]
};
var countOfBackLog = b.issues.filter(x => {
return x.fields.status.name === "Backlog"
}).length
var countOfClose = b.issues.filter(x => {
return x.fields.status.name === "close"
}).length
a =[{Name: 'Backlog', count : countOfBackLog}, {Name: 'close', count : countOfClose}]
More about arrow functions here
You can write like this. It is dynamic.
var a = {};
for(var key in b["issues"]){
if(!a.hasOwnProperty(b["issues"][key].fields.status.name)){
a[b["issues"][key].fields.status.name] = 1;
}else{
a[b["issues"][key].fields.status.name] = a[b["issues"][key].fields.status.name]+1;
}
}
var c = [];
for(var key1 in a){
c.push({
name : key1,
count : a[key1]
});
}
Something like this should do the trick. Simply iterate over your data, keep 2 counters with the number of each type of issue, and create the data format you want in the end. Try it live on jsfiddle.
var b = {
"issues": [{
"fields": {
"status": {
"id": "200",
"name": "Backlog"
}
}
}, {
"fields": {
"status": {
"id": "202",
"name": "close"
}
}
}, {
"fields": {
"status": {
"id": "201",
"name": "close"
}
}
}]
};
var data = [];
for(var issue of b.issues){
var entryFound = false;
var tempObj = {
name: issue.fields.status.name,
count: 1
};
for(var item of data){
if(item.name === tempObj.name){
item.count++;
entryFound = true;
break;
}
}
if(!entryFound){
data.push(tempObj);
}
}
console.log(data);