Related
I am working on an angular application. I have an array as follows:
[{
"Name": "Andy"
},
{
"Name": "Bayer"
},
{
"Name": "James"
},
{
"Name": "Doda"
}]
I have another array which containes data as follows:
[
{
"Name": "Andy",
"Id": "1",
"Time": "2020-06-19T11:02+00:00"
},
{
"Name": "Billy",
"Id": "2",
"Time": "2020-06-19T11:05+00:00"
},
{
"Name": "Ciena",
"Id": 5
"Time": "2020-06-19T11:05+00:00"
},
{
"Name": "Doda",
"Id": "4",
"Time": "2020-06-19T11:05+00:00"
}
]
I want a resultant array such that code should check if Name is present in first array, then it should copy data from second array for that Name and push it in resultant array. For example common name between above two array is Andy and Doda, so data from Andy and Doda should be pushed to resultant array as follows:
[{
"Name": "Andy",
"Id": "1",
"Time": "2020-06-19T11:02+00:00"
},
{
"Name": "Bayer"
},
{
"Name": "James"
},
{
"Name": "Doda",
"Id": "4",
"Time": "2020-06-19T11:05+00:00"
}]
At run time I may get many names so code should be generic. I was trying following code which I got over stackoverflow itself
this.newArray = _.map(this.resultantArray, item => {
const value = _.find(this.dataArray, ['Name', item]);
const obj = value ? value : {Name: item};
return obj;
});
But this code is not working as expected as it works fine for the first time but when data comes for second time it appends data to previous data. I want array to be populated again freshly every time I send data. Please help
You can do this with vanilla JS no need for lodash. You can first map it and inside that you can find the value from second array otherwise return the current object:
var arrayTwo = [ { "Name": "Andy", "Id": "1", "Time": "2020-06-19T11:02+00:00" }, { "Name": "Billy", "Id": "2", "Time": "2020-06-19T11:05+00:00" }, { "Name": "Ciena", "Id": "5", "Time": "2020-06-19T11:05+00:00" }, { "Name": "Doda", "Id": "4", "Time": "2020-06-19T11:05+00:00" } ];
var arrayOne = [{ "Name": "Andy"}, { "Name": "Bayer"}, { "Name": "James"}, { "Name": "Doda"}];
var result = arrayOne.map(val=>arrayTwo.find(p=>p.Name==val.Name) || val);
console.log(result);
Suppose first array name is First
First : any [] = [{"Name": "Andy"},{"Name": "Bayer"},{ "Name": "James"},{"Name": "Doda"}]
And Second array name is Second
Second : any[] = [{"Name": "Andy","Id": "1","Time": "2020-06-19T11:02+00:00"},{"Name": "Bayer"},{"Name": "James"},{"Name": "Doda","Id": "4","Time": "2020-06-19T11:05+00:00"}]
Now do looping and check each name of first if its exists in second copy from second and push in result array
result : any[] =[];
this.First.forEach((element) => {
let index = this.Second.findIndex((x) => element.Name== x.Name);
if (index > -1) {
let data = {
this.Second[index].Name,
this.Second[index].Id,
this.Second[index].time,
};
this.result.push(data);
}
}
As an example - I've included a one element array that contains an object that has a Children key, which is an array of objects and each object also has its' own Children key that contains another array.
[
{
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "10",
"DisplayName": "3-4",
},
{
"Id": "1000",
"DisplayName": "5-6",
},
{
"Id": "100",
"DisplayName": "1-2",
},
]
}
]
}
]
There is a second array of objects that I would like to compare the first array of objects to, with the intention of making sure that the first array is in the same order as the second array of objects, and if it is not - then sort until it is.
Here is the second array:
[
{
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "100",
"DisplayName": "1-2",
},
{
"Id": "10",
"DisplayName": "3-4",
},
{
"Id": "1000",
"DisplayName": "5-6",
},
]
}
]
}
]
The data that this will run on can be up in the tens of thousands - so performance is paramount.
What I'm currently attempting is using a utility method to convert each element of the second array into a keyed object of objects e.g.
{
1: {
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "4",
"DisplayName": "3-4",
},
{
"Id": "3",
"DisplayName": "1-2",
},
]
}
]
}
}
This allows fast look up from the top level. I'm wondering if I should continue doing this all the way down or if there is an idiomatic way to accomplish this. I considered recursion as well.
The order of the already sorted array is not based on Id - it is arbitrary. So the order needs to be preserved regardless.
Assuming same depth and all Id's exist in each level of each object use a recursive function that matches using Array#findIndex() in sort callback
function sortChildren(main, other) {
other.forEach((o, i) => {
if (o.children) {
const mChilds = main[i].children, oChilds = o.children;
oChilds.sort((a, b) => {
return mChilds.findIndex(main => main.Id === a.Id) - mChilds.findIndex(main => main.Id === b.Id)
});
// call function again on this level passing appropriate children arrays in
sortChildren(mChilds, oChilds)
}
})
}
sortChildren(data, newData);
console.log(JSON.stringify(newData, null, ' '))
<script>
var data = [{
"Id": "1",
"Children": [{
"Id": "2",
"Children": [{
"Id": "3",
"DisplayName": "1-2",
},
{
"Id": "4",
"DisplayName": "3-4",
},
]
}]
}]
var newData = [{
"Id": "1",
"Children": [{
"Id": "2",
"Children": [{
"Id": "4",
"DisplayName": "3-4",
},
{
"Id": "3",
"DisplayName": "1-2",
},
]
}]
}]
</script>
I am trying to populate a chart so I'm getting the data into 2 lists in order to do this.
This is the data:
var data = [{
"id": "622",
"name": "some name",
"boats": {
"637": {
"id": "637",
"name": " Subcat 1",
"translations": null
},
"638": {
"id": "638",
"name": "Subcat 2",
"translations": null
}
},
"image": "73e043a7fae04b55855bede22da6286b"
}];
And I am running this code in order to populate the lists:
var chList = [];
var boatList = [];
var boatCount = [];
for (var i = 0; i < data.length; i++) {
var obj = data[i];
var cl = obj.name + " [" + obj.id + "]";
if (obj.boats != null) {
chList.push(cl);
}
if(obj.boats) {
var nme = obj.boats.map( function(item){
return item.name;
});
boatList = boatList.concat(nme);
boatCount.push(nme.length);
}
}
console.log(boatList);
console.log(boatCount);
My problem is that I keep getting:
TypeError: obj.boats.map is not a function
How can I fix this?
Note: The data is actually this:
{
"id": "622",
"name": "some name",
"boats": {
"637": {
"id": "637",
"name": " Subcat 1",
"translations": null
},
"638": {
"id": "638",
"name": "Subcat 2",
"translations": null
}
},
"image": "73e043a7fae04b55855bede22da6286b"
};
But I added [ and ] to it in order to use data.length and the lists where empty too ... Do I then leave this data as it is?
The problem is that obj.boats is an object, not an array, hence doesn't have the map method.
Try this instead:
Object.keys(obj.boats).map(function(k) { return obj.boats[k].name; });
See MDN
boats is an object, not an array. Map is for arrays.
You could use a for ( in ) loop or Object.keys() to get an array of keys and work with that.
The two other answers are right, I'd change the data though:
"boats": [
{
"id": "637",
"name": " Subcat 1",
"translations": null
},
{
"id": "638",
"name": "Subcat 2",
"translations": null
}
],
Using the id as key and then giving the containing object a "id" property is kinda pointless. When you change the data to this structure your code will work fine.
Besides all other answers that already correctly point to obj.boats being an Object and not an Array, I'd like providing a solution that demonstrates the elegant beauty of Array.reduce ...
var boatChartData = [{
"id": "622",
"name": "some name",
"boats": {
"637": {
"id": "637",
"name": "Subcat 1",
"translations": null
},
"638": {
"id": "638",
"name": "Subcat 2",
"translations": null
}
},
"image": "73e043a7fae04b55855bede22da6286b"
}, {
"id": "623",
"name": "other name",
"boats": {
"639": {
"id": "639",
"name": "Supercat",
"translations": null
},
"640": {
"id": "640",
"name": "Supercat II",
"translations": null
},
"641": {
"id": "641",
"name": "Supercat III",
"translations": null
}
},
"image": "73e043a7fae04b55855bede22da6295c"
}];
function collectBoatChartData(collector, chartItem/*, idx, list*/) {
var
boatNameList,
boatMap = chartItem.boats;
if (boatMap != null) {
collector.chartItemTitleList.push([
chartItem.name,
" [",
chartItem.id,
"]"
].join(""));
boatNameList = Object.keys(boatMap).map(collector.getBoatNameByKey, boatMap);
collector.boatNameList = collector.boatNameList.concat(boatNameList);
//collector.chartItemBoatNameList.push(boatNameList);
collector.chartItemBoatCountList.push(boatNameList.length);
}
return collector;
}
var processedBoatChartData = boatChartData.reduce(collectBoatChartData, {
getBoatNameByKey: function (key) {
return this[key].name;
},
boatNameList: [],
chartItemTitleList: [],
//chartItemBoatNameList: [],
chartItemBoatCountList: []
});
console.log("processedBoatChartData.boatNameList : ", processedBoatChartData.boatNameList);
console.log("processedBoatChartData.chartItemTitleList : ", processedBoatChartData.chartItemTitleList);
//console.log("processedBoatChartData.chartItemBoatNameList : ", processedBoatChartData.chartItemBoatNameList);
console.log("processedBoatChartData.chartItemBoatCountList : ", processedBoatChartData.chartItemBoatCountList);
Note
Taking into account the OP's additional comment, mentioning the provided axample's real data structure, the above provided solution of mine just changes to ...
var boatChartData = {
"id": "622",
"name": "some name",
"boats": {
"637": {
"id": "637",
"name": "Subcat 1",
"translations": null
},
"638": {
"id": "638",
"name": "Subcat 2",
"translations": null
}
},
"image": "73e043a7fae04b55855bede22da6286b"
};
var processedBoatChartData = [boatChartData].reduce(collectBoatChartData, {
getBoatNameByKey: function (key) {
return this[key].name;
},
boatNameList: [],
chartItemTitleList: [],
//chartItemBoatNameList: [],
chartItemBoatCountList: []
});
.., proving that generic solutions can be recycled/adapted easily, if e.g. data structures do change.
I'm pretty new to Javascript, and I just learned about underscore.js. I have a deeply nested JSON object, and I need to use underscore to find key/value pairs, which I will then use to populate various HTML tables. If the structure was more shallow, using something like _.pluck would be easy, but I just don't know how to traverse past the first couple of nesting levels (i.e. surveyGDB, table, tablenames). The JSON object comes from an XML that is comprised of multiple nesting structures (mashed up from different database tables).
var JSONData =
"surveyGDB": {
"filename": "..\\Topo\\SurveyGeoDatabase.gdb",
"table": {
"tablename": [
{
"#text": "SurveyInfo\n ",
"record": {
"OBJECTID": "1",
"SiteID": "CBW05583-345970",
"Watershed": "John Day",
"VisitType": "Initial visit",
"SurveyInstrument": "Total Station",
"ImportDate": "2015-07-22T09:08:42",
"StreamName": "Duncan Creek",
"InstrumentModel": "TopCon Magnet v2.5.1",
"FieldSeason": "2015"
}
},
{
"#text": "QaQcPoints\n ",
"record": [
{
"OBJECTID": "1",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "tp",
"Count": "357"
},
{
"OBJECTID": "2",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "tb",
"Count": "92"
},
{
"OBJECTID": "3",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "to",
"Count": "8"
},
{
"OBJECTID": "4",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "bl",
"Count": "279"
},
{
"OBJECTID": "5",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "bf",
"Count": "18"
}
]
},
{
"#text": "QaQcPolygons\n ",
"record": [
{
"OBJECTID": "1",
"TIMESTAMP": "2015-07-22T09:43:08",
"SurveyExtentCount": "",
"WaterExtentCount": "",
"ChannelUnitsCount": "",
"ChannelUnitsUnique": ""
},
{
"OBJECTID": "2",
"TIMESTAMP": "2015-07-22T13:35:15",
"SurveyExtentCount": "1",
"WaterExtentCount": "1",
"ChannelUnitsCount": "21",
"ChannelUnitsUnique": "21"
}
]
}
]
}
}
}
For instance, I wanted all of the values for 'Code' in the 'QaQCPoints' table, so I tried:
var codes = _.flatten(_.pluck(JSONData.surveyGDB.table.tablename[1].record[0], "Code" ));
console.log(codes);
In the console, this returns an array with a length of 5, but with blank values.
What am I doing wrong?
I'd also rather search for the 'Code' values in the table based on something like the '#text' key value, instead of just using it's position in the object.
If I understood you correctly, you want to always search the record array within JSONData.surveyGDB.table.tablename array for some queries. This means you need to find the record based on some parameter and return something from the found record.
Do note that the record property is sometimes an array and sometimes an object (for table SurveyInfo) in your example so I'll assume you need to take this into account.
You can make a small function to extract data and handle both objects and arrays:
function extract(record, prop) {
if (Array.isArray(record)) {
return _.pluck(record, prop);
} else {
return record[prop];
}
}
Usage example:
I wanted all of the values for 'Code' in the 'QaQCPoints' table.
I'd also rather search for the 'Code' values in the table based on something like the '#text' key value, instead of just using it's position in the object.
To achieve this you first find a record using _.find, and then extract Code values from it using the method above:
var table = JSONData.surveyGDB.table.tablename;
// find an item that has `#text` property equal to `QaQcPoints`
var item = _.find(table, function(r) {
return r['#text'] === 'QaQcPoints';
});
// extract codes from the found item's record property
var code = extract(item.record, 'Code');
// output ["tp", "tb", "to", "bl", "bf"]
Running sample:
var JSONData = {
"surveyGDB": {
"filename": "..\\Topo\\SurveyGeoDatabase.gdb",
"table": {
"tablename": [{
"#text": "SurveyInfo",
"record": {
"OBJECTID": "1",
"SiteID": "CBW05583-345970",
"Watershed": "John Day",
"VisitType": "Initial visit",
"SurveyInstrument": "Total Station",
"ImportDate": "2015-07-22T09:08:42",
"StreamName": "Duncan Creek",
"InstrumentModel": "TopCon Magnet v2.5.1",
"FieldSeason": "2015"
}
}, {
"#text": "QaQcPoints",
"record": [{
"OBJECTID": "1",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "tp",
"Count": "357"
}, {
"OBJECTID": "2",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "tb",
"Count": "92"
}, {
"OBJECTID": "3",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "to",
"Count": "8"
}, {
"OBJECTID": "4",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "bl",
"Count": "279"
}, {
"OBJECTID": "5",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "bf",
"Count": "18"
}]
}, {
"#text": "QaQcPolygons",
"record": [{
"OBJECTID": "1",
"TIMESTAMP": "2015-07-22T09:43:08",
"SurveyExtentCount": "",
"WaterExtentCount": "",
"ChannelUnitsCount": "",
"ChannelUnitsUnique": ""
}, {
"OBJECTID": "2",
"TIMESTAMP": "2015-07-22T13:35:15",
"SurveyExtentCount": "1",
"WaterExtentCount": "1",
"ChannelUnitsCount": "21",
"ChannelUnitsUnique": "21"
}]
}]
}
}
}
function extract(record, prop) {
if (Array.isArray(record)) {
return _.pluck(record, prop);
} else {
return record[prop];
}
}
var table = JSONData.surveyGDB.table.tablename;
var item = _.find(table, function(r) {
return r['#text'] === 'QaQcPoints';
});
console.dir(item);
var code = extract(item.record, 'Code');
console.log(code);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
You have a two stage problem. Stage one is figuring out which table is QaQcPoints. If that's always JSONData.surveyGDB.table.tablename[1], you're good.
The next stage is getting your data out. You can use native array manipulation most of the time (unless you're on really old browsers). So:
var table = JSONData.surveyGDB.table.tablename[1].record;
var codeArray = table.map(function(val) { return val.Code; });
Will do the trick.
I have a question about the Graph API.
I use Javascript for the API and make a little test website ,where you can log in ,look for new messages and write a new status.
My problem is that I can't get the messages or the thread.
FB.api('/me/inbox',function(response) { alert(response.id); } ); don't work.
Have somebody an example for getting the messages in the inbox??
Thanks
The /me/inbox request requires that you have the read_mailbox permission granted.
Once you've got that, the /me/inbox request will return an array of Thread's, which will look something like this;
{
"data": [
{
"id": "1126884978255",
"from": {
"name": "Someone's Name",
"id": "34723472"
},
"to": {
"data": [
{
"name": "Someone's Name",
"id": "34723472"
},
{
"name": "Matt Lunn",
"id": "560914724"
}
]
},
"message": "Testing the one-ness.",
"updated_time": "2012-01-31T12:13:00+0000",
"unread": 0,
"unseen": 0,
"comments": {
"data": [
{
"id": "1126884978255_6769",
"from": {
"name": "Someone's Name",
"id": "34723472"
},
"message": "£140!?",
"created_time": "2012-01-31T11:33:15+0000"
},
{
"id": "1126884978255_6771",
"from": {
"name": "Matt Lunn",
"id": "560914724"
},
"message": "^^ month in advance as well",
"created_time": "2012-01-31T11:33:26+0000"
}
]
},
"type": "thread"
}
],
"summary": {
"unseen_count": 0,
"unread_count": 21,
"updated_time": "2012-01-31T13:19:31+0000"
}
}
So depending which ID you're after, you'll have to do;
for (var i=0;i<response.data.length;i++) {
var thread = response.data[i];
for (var j=0;j<thread.comments.data.length;j++) {
var comment = thread.comments.data[j];
console.log(comment.message);
}
}
Hopefully you get the idea...