I need to get the title of interval but my function returns undefined.
Function
filterByCategories () {
return _.orderBy(this.meetups.filter(item => {
console.log('title: ' + JSON.stringify(item.interval.title, null, 4))
JSON (content of this.meetups):
[
{
"id": "-12345",
"title": "abcds",
"description": "Hello3",
"date": "2023-12-29",
"location": {
"color": "grey darken-2",
"icon": "not_interested",
"id": "none",
"title": ""
},
"creatorId": "abcd1234",
"time": "24:00",
"color": {
"color": "red darken-2",
"id": "06",
"title": "Ret"
},
"interval": {
"color": "green darken-2",
"icon": "local_activity",
"title": "Weekly",
"value": 3
},
"statusType": false,
"pause": false,
"pushNotification": false
}
]
How to read the title of interval?
Since the json is already parsed, you can simply just access it by it's property name. Keep in mind, the data is within an array so there will be multiple .interval.title. Using a for loop is probably a better option here unless you're after a certain index. If you are after a certain index, forget the for loop and just do json[0].interval.name (0 being the index you're after);
const json = [
{
"id": "-12345",
"title": "abcds",
"description": "Hello3",
"date": "2023-12-29",
"location": {
"color": "grey darken-2",
"icon": "not_interested",
"id": "none",
"title": ""
},
"creatorId": "abcd1234",
"time": "24:00",
"color": {
"color": "red darken-2",
"id": "06",
"title": "Ret"
},
"interval": {
"color": "green darken-2",
"icon": "local_activity",
"title": "Weekly",
"value": 3
},
"statusType": false,
"pause": false,
"pushNotification": false
}
];
for (let i = 0; i < json.length; i++) {
const meetup = json[i];
console.log(meetup.interval.title);
}
Try this, if there are multiple objects in meetups, you can use Array.map to iterate over the array of objects, and print out the value of the title property within interval?
this.meetups.map(obj => {
console.log(`title: ${obj['interval']['title']}`);
});
Or simply this, if there is only 1 object in meetups?
this.meetups[0]['interval']['title']
Demo:
const meetups =[{"id":"-12345","title":"abcds","description":"Hello3","date":"2023-12-29","location":{"color":"grey darken-2","icon":"not_interested","id":"none","title":""},"creatorId":"abcd1234","time":"24:00","color":{"color":"red darken-2","id":"06","title":"Ret"},"interval":{"color":"green darken-2","icon":"local_activity","title":"Weekly","value":3},"statusType":false,"pause":false,"pushNotification":false}];
meetups.map(obj => {
console.log(`title: ${obj['interval']['title']}`);
});
Regarding the code you have provided on your question, I am unsure why did you use Array.filter(), as what it does is that it returns a new array based on the callback function you have provided within filter(). In addition, stringifying it using JSON.stringify() will turn that array into a string, which kind of defeats the purpose of accessing the values within the array of objects.
Related
I've been playing around trying to learn in an API project using Postman and conducting tests using JavaScript. So far, I have succeeded with the help of reading on websites and watching YouTube videos. Of course, previous tests and playing around have been fairly easy but now I came to a stop. I really tried to figure this out for several weeks but I need further guidance, a push in the right direction or direct help.
What I'm trying to do is to filter out some of the response to only view objects that contain specific data.
To do that, I'm using a filter where I want all products containing a specific value inside an array "product_option_values".
My first approach was to see if I could sort products having any values from the first array, and it worked. It filters just fine.
var filterSmall = jsonData.products.filter(fs => fs.associations.product_option_values);
My next approach was to get to my goal of filtering out products according to specific values inside this array. I tried many simple .(dot) combinations and pointing to [index] to access it without any luck. (I must add that I know how to access this from a specific product, but that way doesn't work when filtering).
I've also tried other approaches such as:
var filterSmall = jsonData.products.filter(fs => fs.associations["product_option_values", 0, "name"] === "S");
and other similar combinations.
This is a very shortened sample of the structure of "products" which in its full form consists of 20 products and far more values inside of it:
{
"products": [
{
"id": 16,
"manufacturer_name": "Graphic Corner",
"quantity": "0",
"price": "12.900000",
"indexed": "1",
"name": "Mountain fox notebook",
"associations": {
"categories": [
{
"id": "2"
},
{
"id": "6"
}
],
"product_option_values": [
{
"id": "22"
},
{
"id": "23"
}
]
}
},
{
"id": 17,
"manufacturer_name": "Graphic Corner",
"quantity": "0",
"price": "12.900000",
"indexed": "1",
"name": "Brown bear notebook",
"associations": {
"categories": [
{
"id": "2"
},
{
"id": "6"
}
],
"product_option_values": [
{
"id": "23"
},
{
"id": "24"
}
]
}
}
]
}
and here is a small and expanded sample from product_option_values:
{
"product_option_values": [
{
"id": 1,
"id_attribute_group": "1",
"color": "",
"position": "0",
"name": "S"
},
{
"id": 2,
"id_attribute_group": "1",
"color": "",
"position": "1",
"name": "M"
},
{
"id": 3,
"id_attribute_group": "1",
"color": "",
"position": "2",
"name": "L"
}
]
}
How do I proceed? Did I do anything correct or even close to it?
Perhaps I've been staring at this for too long.
Thanks in advance.
If you want to compare nested attributes you have to transform the objects (e.g. by using a map operation), so that the relevant attributes are easily accessible for a comparison. If you want to filter by product_option_value id, you could do something like this:
const jsonData = {
"products": [
{
"id": 16,
"manufacturer_name": "Graphic Corner",
"quantity": "0",
"price": "12.900000",
"indexed": "1",
"name": "Mountain fox notebook",
"associations": {
"categories": [
{
"id": "2"
},
{
"id": "6"
}
],
"product_option_values": [
{
"id": "22"
},
{
"id": "23"
}
]
}
},
{
"id": 17,
"manufacturer_name": "Graphic Corner",
"quantity": "0",
"price": "12.900000",
"indexed": "1",
"name": "Brown bear notebook",
"associations": {
"categories": [
{
"id": "2"
},
{
"id": "6"
}
],
"product_option_values": [
{
"id": "23"
},
{
"id": "24"
}
]
}
}
]
};
const sample = {
"product_option_values": [
{
"id": 22,
"id_attribute_group": "1",
"color": "",
"position": "0",
"name": "S"
},
{
"id": 2,
"id_attribute_group": "1",
"color": "",
"position": "1",
"name": "M"
},
{
"id": 3,
"id_attribute_group": "1",
"color": "",
"position": "2",
"name": "L"
}
]
};
const ids = sample.product_option_values.map((el) => String(el.id));
console.log(ids);
const filtered = jsonData.products.filter((fs) => fs.associations.product_option_values.map((e) => e.id).some((f) => ids.includes(f)));
console.log(filtered);
I've created a cart to which items can be added or removed. At some point in my app I'm displaying this cart, which will have max 3 items. However, the order of the items change as I add/remove from the cart.
{cartItems.map( item => <p key={`${item.type}-${item.id}`}>{item.name || item.time}</p>)}
The items being added have a type property which could be used for setting an order, but I've not been able to use it in my favour.
Two examples of items:
{
"id": "0",
"type": "service",
"name": "Painting",
"isFavorite": false
}
{
"id": "0",
"type": "time",
"day": "today",
"time": "09:40",
"isFavorite": false
}
how can I always display object with 'time' type before 'service'?
const array = [{
"id": "0",
"type": "service",
"name": "Painting",
"isFavorite": false
},
{
"id": "1",
"type": "time",
"day": "today",
"time": "09:40",
"isFavorite": false
}, {
"id": "2",
"type": "time",
"day": "yesterday",
"time": "09:30",
"isFavorite": false
}, {
"id": "3",
"type": "service",
"name": "Some Service",
"isFavorite": false
}
];
const sortedArray = array.reduce((acc, object) => {
const method = 'time' in object ? 'unshift' : 'push';
acc[method](object);
return acc;
}, []);
console.log(sortedArray);
You can write a simple comparison function, which you then use in the array sort.
function compare(a, b) {
if (a.type === b.type) return 0;
else if (a.type === 'time') return -1;
return 1;
}
var cartItems = [{
"id": "0",
"type": "service",
"name": "Painting",
"isFavorite": false
}, {
"id": "0",
"type": "time",
"day": "today",
"time": "09:40",
"isFavorite": false
}]
cartItems.sort(compare);
And then you can simply call your map on sortedItems as before
{cartItems.map( item => <p key={`${item.type}-${item.id}`}>{item.name || item.time}</p>)}
Good afternoon.
I have required json, which contains the basic template for the layout of Adaptive Cards (bot framework).
Here's this json:
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0",
"type": "AdaptiveCard",
"speak": "",
"body": [
{
"type": "TextBlock",
"horizontalAlignment": "center",
"text": "Все машины",
"weight": "bolder",
"isSubtle": false
},
{
"type": "TextBlock",
"text": "Внимание, вы вошли в режим тендера.",
"separator": true
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Подтвердить лот(ы)",
"data": {
"msteams": {
"type": "messageBack",
"displayText": "Идет подтверждение ваших лотов, ожидайте!",
"text": "/accept",
"value": "{\"x\": \"bfVal\", \"y\": \"from value\"}"
}
}
},
{
"type": "Action.Submit",
"title": "Отменить все лоты",
"data": {
"x": "123",
"msteams": {
"type": "messageBack",
"displayText": "Идет отменение ваших лотов, ожидайте!",
"text": "/cancel",
"value": "{\"bfKey\": \"bfVal\", \"conflictKey\": \"from value\"}"
}
}
}
]
}
I also have a loop that takes data from my source and forms another json from it.
try {
// Pull in the data from Microsoft Graph.
const client = new SimpleGraphClient(tokenResponse.token);
const me = await client.getList();
var i = 0;
while (i < me['value'].length) {
feed = {
"type": "ColumnSet",
"separator": true,
"columns": [
{
"type": "Column",
"width": 1,
"items": [
{
"type": "TextBlock",
"text": "Продукт",
"isSubtle": true
},
{
"type": "TextBlock",
"size": "extraLarge",
"color": "accent",
"text": me.value[i].fields.Good,
"spacing": "none"
},
{
"type": "TextBlock",
"text": "Дата: " + dateFormat(me.value[i].fields.ShipmentDateTime, 'dd-mm-yyyy'),
"spacing": "yes"
}
]
},
{
"type": "Column",
"width": "auto",
"items": [
{
"type": "TextBlock",
"text": " "
},
{
"type": "Image",
"url": "https://png.pngtree.com/svg/20170614/engine_oil_410031.png",
"size": "medium",
"spacing": "yes"
},
{
"type": "TextBlock",
"text": " ID: " + me.value[i].fields.id,
"value": me.value[i].fields.id
}
]
},
{
"type": "Column",
"width": 1,
"items": [
{
"type": "TextBlock",
"horizontalAlignment": "right",
"text": "RUB",
"isSubtle": true
},
{
"type": "TextBlock",
"horizontalAlignment": "right",
"size": "extraLarge",
"color": "accent",
"text": me.value[i].fields.PricePerTon,
"spacing": "none"
},
{
"type": "Input.Toggle",
"title": "Приобрести лот",
"valueOn": "true",
"valueOff": "false",
"id": "buyGood",
"spacing": "yes"
}
]
}
]
}
tender.body.push(feed);
i++;
}
Then I combine these json.
This works well, but when you retrieve the data again, the data is doubled.
How can this be resolved?
Thanks in advance.
It looks like every time you create a new card, you are appending the JSON object you created in the while loop to your required JSON object. Consequently, the next time you try to create a new card, the data from the previous request is still stored in your required JSON object. To avoid this, create a copy of the required JSON Object and store it in a different variable before your while loop. You can use JSON.parse(JSON.stringify(obj)) to create a copy of a JSON Object.
Your code should look something like this:
// create a copy of the required JSON Object
// and store it in a new variable
const card = JSON.parse(JSON.stringify(tender));
var i = 0;
while (i < me['value'].length) {
let feed = {
"type": "ColumnSet",
"separator": true,
...
}
// push feed to `card` instead of `tender`
card.body.push(feed);
i++;
}
...
// send `card` to user instead of `tender`
await turnContext.sendActivity({
text: "Double Data Card",
attachments: [CardFactory.adaptiveCard(card)]
});
Here is my array objects
var skus = [
{
"id": "1",
"active": true,
"attributes": {
"color": "pink",
"size": "small",
"material": "plastic"
},
"price": 899
},{
"id": "2",
"object": "sku",
"active": true,
"attributes": {
"color": "blue",
"size": "medium",
"material": "plastic"
},
"price": 500
},{
"id": "3",
"object": "sku",
"active": true,
"attributes": {
"color": "blue",
"size": "medium",
"material": "metal"
},
"price": 600
}
]
I want the output something like this :
finalOutput = {
"plastic" : [{id:1,...},{id:2,...}],
"metal" : [{id:3,...}]
}
So basically, I want to merge all the objects which have same attributes.material value.
Use lodash's _.groupBy() to collect the objects by their attributes.material.
var skus = [{"id":"1","active":true,"attributes":{"color":"pink","size":"small","material":"plastic"},"price":899},{"id":"2","object":"sku","active":true,"attributes":{"color":"blue","size":"medium","material":"plastic"},"price":500},{"id":"3","object":"sku","active":true,"attributes":{"color":"blue","size":"medium","material":"metal"},"price":600}];
var result = _.groupBy(skus, 'attributes.material');
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
... ok, let's have a look at Usman's approach ...
var skus = [{ "id": "1", "active": true, "attributes": { "color": "pink", "size": "small", "material": "plastic" }, "price": 899 }, { "id": "2", "object": "sku", "active": true, "attributes": { "color": "blue", "size": "medium", "material": "plastic" }, "price": 500 }, { "id": "3", "object": "sku", "active": true, "attributes": { "color": "blue", "size": "medium", "material": "metal" }, "price": 600 }];
var obj = {};
skus.forEach(o => {
if(!obj.hasOwnProperty(o.attributes.material)) {
obj[o.attributes.material] = [o];
} else {
obj[o.attributes.material].push(o);
}
});
console.log(obj);
.as-console-wrapper { max-height: 100%!important; top: 0; }
... it is based on an external object obj that serves both purposes, being the final result but also being the collecting reference for the time of iterating the given data structure skus.
Then there is a lookup for an existing property/key on obj that does match the value of a certain substructure of skus. In case obj does not yet features this key, an array gets assigned to a newly created property. This array already holds a single item, the current object of the skus iteration.
If the property already exists - by then it references an array - the current object of the skus iteration just will be pushed into this array.
Having finished the forEach iteration of skus, obj will hold one or more lists of former skus-items, each mapped to a single key/property of unique attributes.material-values derieved from skus-items.
A good solution provides a function that encloses all of this code.
An even better solution will come up with a more generic and better reusable approach. Since the whole matter is about transforming list based data structures, map and reduce are good candidates for it. Here the latter is the right one for map only is capable of mapping one list item into just another one, thus it does not change the list itself but it transforms each of a list's items. reduce is far more flexible for it provides into it's callback a collector/accumulator object in addition to the currently iterated item. This collector can be provided as initial value and it's type/structure is free of choice.
A reduce based approach that meets the OP's requirements needs to be customizable in terms of how to access a certain property that's value then is base of a (gouped) list of objects that share this special property value.
A working example then might look like the next provided one ...
var skus = [{ "id": "1", "active": true, "attributes": { "color": "pink", "size": "small", "material": "plastic" }, "price": 899 }, { "id": "2", "object": "sku", "active": true, "attributes": { "color": "blue", "size": "medium", "material": "plastic" }, "price": 500 }, { "id": "3", "object": "sku", "active": true, "attributes": { "color": "blue", "size": "medium", "material": "metal" }, "price": 600 }];
function collectItemGroupedByGenericKey(collector, item) {
var
groupKey = collector.getGroupKey(item),
store = collector.store,
storedList = store[groupKey];
if (!storedList) {
storedList = store[groupKey] = [];
}
storedList.push(item);
return collector;
}
var materialList = skus.reduce(collectItemGroupedByGenericKey, {
getGroupKey: function (item) { return item.attributes.material; },
store: {}
}).store;
console.log('materialList : ', materialList);
.as-console-wrapper { max-height: 100%!important; top: 0; }
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.