Related
In grouped result I need the property of vendor and store in new array. but the give me some error. the error is Error: words is not defined.
how can I get vendor property from grouped list?
it is about to get result and store in new property.
const cart = {
"_id": 2,
"owner": 7,
"products": [{
"_id": {
"$oid": "5f06f9a4b8b878050fbc54b2"
},
"product": 1,
"vendor": 1,
"quantity": 2
}, {
"_id": {
"$oid": "5f06f9a4b8b878050fbc54b3"
},
"product": 2,
"vendor": 1,
"quantity": 1
}, {
"_id": {
"$oid": "5f06f9a4b8b878050fbc54b4"
},
"product": 4,
"vendor": 2,
"quantity": 1
}],
"createdAt": {
"$date": "2020-06-21T06:46:40.111Z"
},
"updatedAt": {
"$date": "2020-07-09T11:04:04.459Z"
},
"__v": 0,
"totalPrice": 265
}
const product = cart.products;
var grouped = product.reduce((dictionary, p) => {
dictionary[p.vendor] = dictionary[p.vendor] || [];
dictionary[p.vendor].push(p);
return dictionary;
}, {})
for (const p in grouped) {
console.log(grouped[p].vendor)
}
const cart = {
_id: 2,
owner: 7,
products: [
{
_id: {
$oid: "5f06f9a4b8b878050fbc54b2",
},
product: 1,
vendor: 1,
quantity: 2,
},
{
_id: {
$oid: "5f06f9a4b8b878050fbc54b3",
},
product: 2,
vendor: 1,
quantity: 1,
},
{
_id: {
$oid: "5f06f9a4b8b878050fbc54b4",
},
product: 4,
vendor: 2,
quantity: 1,
},
],
createdAt: {
$date: "2020-06-21T06:46:40.111Z",
},
updatedAt: {
$date: "2020-07-09T11:04:04.459Z",
},
__v: 0,
totalPrice: 265,
};
// const result = words.filter((word) => word.length > 6); // useless line, you do not have variable 'words'
const f = cart.products.filter((p) => p.vendor == 1);
const products = cart.products; //better variable naming
var grouped = products.reduce((dictionary, p) => {
dictionary[p.vendor] = dictionary[p.vendor] || [];
dictionary[p.vendor].push(p);
return dictionary;
}, {});
for (const p in grouped) {
console.log(grouped[p]); //is array
}
To fix this code just delete the line where you use variable words coz you didn't declare such.
To get vendor value:
grouped[p] is an array. It doesn't have a property vendor. But you can get it with:
for (const p in grouped) {
console.log(grouped[p][0].vendor);
}
or get an array of them:
let vendors = Object.getOwnPropertyNames(grouped);
Aside from the 2 lines of code which do nothing, I think you're trying to get the id of the vendor for each group - in which case this is just p in your code at the bottom which logs:
const cart = {"_id":2,"owner":7,"products":[{"_id":{"$oid":"5f06f9a4b8b878050fbc54b2"},"product":1,"vendor":1,"quantity":2},{"_id":{"$oid":"5f06f9a4b8b878050fbc54b3"},"product":2,"vendor":1,"quantity":1},{"_id":{"$oid":"5f06f9a4b8b878050fbc54b4"},"product":4,"vendor":2,"quantity":1}],"createdAt":{"$date":"2020-06-21T06:46:40.111Z"},"updatedAt":{"$date":"2020-07-09T11:04:04.459Z"},"__v":0,"totalPrice":265}
//const result = words.filter(word => word.length > 6);
//const f = cart.products.filter(p => p.vendor == 1);
const product = cart.products;
var grouped = product.reduce((dictionary, p) => {
dictionary[p.vendor] = dictionary[p.vendor] || [];
dictionary[p.vendor].push(p);
return dictionary;
}, {})
let vendor;
for (const p in grouped) {
console.log("vendor=", p, " count of items=", grouped[p].length)
}
I think this will give you the result you are looking for:
let f = cart.products.map( p => p.vendor);
let newArray = f.filter((vendor,index,arr)=>vendor!==arr[index+1]);
newArray.forEach(element => {
console.log(element);
});
You have some extraneous code in your script.
const result = words.filter(word => word.length > 6);
On line 36 you write const result = words.filter(word => word.length > 6); but words is not defined anywhere in your code and that is what generates the error.
For what concerns what you want to achieve, I am not entirely sure I understood it but, if I did, you can solve your issue like this:
const cart = {
"_id": 2,
"owner": 7,
"products": [{
"_id": {
"$oid": "5f06f9a4b8b878050fbc54b2"
},
"product": 1,
"vendor": 1,
"quantity": 2
}, {
"_id": {
"$oid": "5f06f9a4b8b878050fbc54b3"
},
"product": 2,
"vendor": 1,
"quantity": 1
}, {
"_id": {
"$oid": "5f06f9a4b8b878050fbc54b4"
},
"product": 4,
"vendor": 2,
"quantity": 1
}],
"createdAt": {
"$date": "2020-06-21T06:46:40.111Z"
},
"updatedAt": {
"$date": "2020-07-09T11:04:04.459Z"
},
"__v": 0,
"totalPrice": 265
}
const products = cart.products;
const vendors = products
.map(product => product.vendor)
.reduce((vendors, vendor) => {
if (vendors.indexOf(vendor) < 0) {
vendors.push(vendor);
}
return vendors;
}, []);
const productsByVendor = products.reduce((dictionary, p) => {
dictionary[p.vendor] = dictionary[p.vendor] || [];
dictionary[p.vendor].push(p);
return dictionary;
}, {});
console.log('Products grouped by vendor:\n', productsByVendor);
// in 'productsByVendor' the vendors are the keys of your object
console.log('Vendors:', Object.keys(productsByVendor));
/* if you want to retrieve the vendor of a specific product from 'productsByVendor'
* Assumptions:
* 1. cart.products[n].product is assumed to be a unique id (if that is not the case, you can use cart.products[n]._id instead)
* 2. I am assuming that each product can be sold by only one vendor; if a product can be sold by more than one vendor you'll have to adjust a bit the function
*/
getVendorIdFromGroupedProducts = (productId) => {
for (let key of Object.keys(productsByVendor)) {
for (let prod of productsByVendor[key]) {
if (prod.product === productId) {
return prod.vendor
}
}
}
return 'The product does not exist'
};
console.log('Vendor of product 1 is:', getVendorIdFromGroupedProducts(1));
console.log('Vendor of product 2 is:', getVendorIdFromGroupedProducts(2));
console.log('Vendor of product 3 is:', getVendorIdFromGroupedProducts(3));
console.log('Vendor of product 4 is:', getVendorIdFromGroupedProducts(4));
I have to check if any of the "cuesData" has a value or length greater than 0.
In my code below, i can only check the first array but not the others.
TS
checkValues(values) {
const result = Object.values(values).every((value) => value[1].cuesData.length > 0);
return result;
}
HTML
<div *ngIf="checkValues(values) === true">
JSON
[
[
"videoData__1",
{
"id": 1,
"title": "Pale Blue Dot",
"stoppedAt": 97.834667,
"cuesData": [
{
"startTime": 25.335678,
"endTime": 35.335678,
"description": "fqff"
}
]
}
],
[
"videoData__2",
{
"id": 2,
"title": "Big Buck Bunny",
"stoppedAt": 247.57881,
"cuesData": []
}
],
[
"videoData__3",
{
"id": 3,
"title": "Elephants Dream",
"stoppedAt": 404.585327,
"cuesData": []
}
]
]
Change,
checkValues(values) {
const result = Object.values(values).every((value) => value[1].cuesData.length > 0);
return result;
}
To
checkValues(values){
const result = Object.values(values).some((value) => value[1].cuesData.length > 0);
return result;
}
Working Stackblitz: https://stackblitz.com/edit/my-angular-starter-j4yypu
Here .every() method will check that all conditions should met but whereas some() method works that at least one condition has been true..
Stackblitz without cuesdata length: https://stackblitz.com/edit/my-angular-starter-cfpxa5
You can use some method for this:
*ngIf="CheckValues(values)"
function:
CheckValues(values : any[]){
return values.some(v=>v[1].cuesData&&v[1].cuesData.length); //if any array has cuesData, some will return true
}
more about some : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
I'd like to map this table's chapter_id and brother_id with the brothers and chapters table below and return the brothername and name field's respectively. Using js or jquery. I am using vuejs returning minutes array as a computed property. See below.
In sql it's be something like
select brothername from brothers where minute.brother_id = brothers.id ... and then set the brothername as the new value for brother_id
same thing goes for chapter_id:
select brothername from brothers where minute.brother_id = brothers.id ... and then set the brothername as the new value for brother_id
the resulting array or object should be:
Expected Array
[
{
"location":"UCLA",
"chapter_id":"Beta",
"brother_id":"Golpher",
"created_at":"2008-05-15 22:23:00",
"status":"Approved"
},
{ ... },
{
"location":"John's Deli",
"chapter_id":"Beta", notice the change in the array based on the ids
"brother_id":"Sheera", notice the change in the array based on the ids
"created_at":"2008-05-15 22:23:00",
"status":"Approved"
}
]
Minutes Table (original array)
[
{
"location":"UCLA",
"chapter_id":2,
"brother_id":1,
"created_at":"2008-05-15 22:23:00",
"status":"Approved"
},
{ ... },
{
"location":"John's Deli",
"chapter_id":2,
"brother_id":4,
"created_at":"2008-05-15 22:23:00",
"status":"Approved"
}
]
Chapter's Table
[
{
"id":1,
"letter_representation":"A",
"name":"Alpha",
"founded_at":"UCLA",
...
},
{ ... }
]
Brother's Table
[
{
"id":1,
"profile_id":1,
"chapter_id":1,
"brothername":"Golpher",
"firstname":"Jack",
...
},
{ ... },
{
"id":4,
"profile_id":4,
"chapter_id":1,
"brothername":"Sheera",
"firstname":"Jake",
...
}
]
Vue.js
computed: {
brothers () {
return this.$store.state.brothers
},
chapters () {
return this.$store.state.chapters
},
minutes () {
return this.$store.getters.model
}
},
I assume that you don't want to mutate objects in the original arrays with this operation.
Note You may want to handle the case where brother_id or chapter_id doesn't exist in the corresponding table. In the below example, it just sets the property value to undefined
const minutesTable = [{
"location": "UCLA",
"chapter_id": 2,
"brother_id": 1,
"created_at": "2008-05-15 22:23:00",
"status": "Approved"
}, {
"location": "John's Deli",
"chapter_id": 2,
"brother_id": 4,
"created_at": "2008-05-15 22:23:00",
"status": "Approved"
}]
const chapterTable = [{
"id": 1,
"letter_representation": "A",
"name": "Alpha",
"founded_at": "UCLA",
}]
const brotherTable = [{
"id": 1,
"profile_id": 1,
"chapter_id": 1,
"brothername": "Golpher",
"firstname": "Jack",
}, {
"id": 4,
"profile_id": 4,
"chapter_id": 1,
"brothername": "Sheera",
"firstname": "Jake",
}]
// your result
const result = minutesTable.map(m => {
const brother = brotherTable.find(b => b.id === m.brother_id)
const chapter = chapterTable.find(c => c.id === m.chapter_id)
return Object.assign({}, m, {
brother_id: brother && brother.brothername,
chapter_id: chapter && chapter.name,
})
})
console.log(result)
This should be what you need
const minutesTable = [
{
"location":"UCLA",
"chapter_id":2,
"brother_id":1,
"created_at":"2008-05-15 22:23:00",
"status":"Approved"
},
{
"location":"John's Deli",
"chapter_id":2,
"brother_id":4,
"created_at":"2008-05-15 22:23:00",
"status":"Approved"
}
]
const chapterTable =
[
{
"id":1,
"letter_representation":"A",
"name":"Alpha",
"founded_at":"UCLA",
}
]
const brotherTable = [
{
"id":1,
"profile_id":1,
"chapter_id":1,
"brothername":"Golpher",
"firstname":"Jack",
},
{
"id":4,
"profile_id":4,
"chapter_id":1,
"brothername":"Sheera",
"firstname":"Jake",
}
]
/* code starts here */
let newMinutesTable = JSON.parse(JSON.stringify(minutesTable)).map(a => {
let brother = brotherTable.find(id => id.id === a.brother_id);
let chapter = chapterTable.find(id => id.id === a.chapter_id)
if (brother) a.brother_id = brother.brothername
if (chapter) a.chapter_id = chapter.name;
return a;
})
console.log([minutesTable,newMinutesTable]);
I think you should prepare those values first just to better understanding. So I made this, let me explain in pieces.
Your input information:
var minutesTable = [{
"location": "UCLA",
"chapter_id": 2,
"brother_id": 1,
"created_at": "2008-05-15 22:23:00",
"status": "Approved"
}, {
"location": "John's Deli",
"chapter_id": 2,
"brother_id": 4,
"created_at": "2008-05-15 22:23:00",
"status": "Approved"
}],
chapterTable = [{
"id": 1,
"letter_representation": "A",
"name": "Alpha",
"founded_at": "UCLA",
}],
brotherTable = [{
"id": 1,
"profile_id": 1,
"chapter_id": 1,
"brothername": "Golpher",
"firstname": "Jack",
}, {
"id": 4,
"profile_id": 4,
"chapter_id": 1,
"brothername": "Sheera",
"firstname": "Jake",
}];
Somehow you'll be forced to take this information as variables. We will work with that.
Preparing data
Dealing with array of objects it's a litle bit complicated when you need to look for unique informations on each object from distinct arrays especially if you want to run this more than once. So instead of working with arrays of objects we can save our lifes changing that to objects of objects, where each item index must be that unique IDs. Look:
var chapters = {},
brothers = {};
chapterTable.map(function(el, i) {
chapters[el.id] = el;
});
brotherTable.map(function(el, i) {
brothers[el.id] = el;
});
Now you can easily find a chapter by chapter_id or a brother by brother_id, right? Then you can finish the problem like this:
var output = [];
minutesTable.map(function(el, i) {
var item = {
"location": el.location, // note that values are just default values, just in case
"chapter_id":"-",
"brother_id":"-",
"created_at": el.created_at,
"status": el.status
};
// PS: you need to check if that brother_id really exists!
if(brothers[el.brother_id] != undefined) {
item.brother_id = brothers[el.brother_id].brothername;
}
// PS: the same with chapters
if(chapters[el.chapter_id] != undefined) {
item.chapter_id = chapters[el.chapter_id].name;
}
output.push(item);
});
That's it. Anyway, if you can change your SQL queries, would be better to work with SQL joins and prepare your values there.
I am an Angular novice and am learning a little by trying to pull the evolution chain for each pokemon using pokeapi but having a difficult time because of deep nesting.
A typical response object is returned like this:
{
"baby_trigger_item": null,
"id": 2,
"chain": {
"evolution_details": [],
"evolves_to": [
{
"evolution_details": [
{
"min_level": 16,
"min_beauty": null,
"time_of_day": "",
"gender": null,
"relative_physical_stats": null,
"needs_overworld_rain": false,
"turn_upside_down": false,
"item": null,
"trigger": {
"url": "http://pokeapi.co/api/v2/evolution-trigger/1/",
"name": "level-up"
},
"known_move_type": null,
"min_affection": null,
"party_type": null,
"trade_species": null,
"party_species": null,
"min_happiness": null,
"held_item": null,
"known_move": null,
"location": null
}
],
"evolves_to": [
{
"evolution_details": [
{
"min_level": 36,
"min_beauty": null,
"time_of_day": "",
"gender": null,
"relative_physical_stats": null,
"needs_overworld_rain": false,
"turn_upside_down": false,
"item": null,
"trigger": {
"url": "http://pokeapi.co/api/v2/evolution-trigger/1/",
"name": "level-up"
},
"known_move_type": null,
"min_affection": null,
"party_type": null,
"trade_species": null,
"party_species": null,
"min_happiness": null,
"held_item": null,
"known_move": null,
"location": null
}
],
"evolves_to": [],
"is_baby": false,
"species": {
"url": "http://pokeapi.co/api/v2/pokemon-species/6/",
"name": "charizard"
}
}
],
"is_baby": false,
"species": {
"url": "http://pokeapi.co/api/v2/pokemon-species/5/",
"name": "charmeleon"
}
}
],
"is_baby": false,
"species": {
"url": "http://pokeapi.co/api/v2/pokemon-species/4/",
"name": "charmander"
}
}
}
I have to get to evolves_to property, and grab species.name as well as evolution_details.min_level and evolution_details.trigger.name, and evolution_details.item if not null
But as you can see, the evolves_to property, itself contains another evolves_to nested inside, which has another nested inside
This is my sad attempt (after http.get) and I'm just stuck now.
var evoObject = response.data;
function loopEvo(obj){
angular.forEach(obj, function(value, key, object){
if (key == 'evolves_to' && value != []) {
//from here I can get top level data, but...
}
});
}
loopEvo(evoObject.chain);
I don't know how to recursively dive into objects and continually grab data, can anyone provide any help? I would love to use this as a great learning opportunity in traversing complex json objects.
You could always just avoid using Angular and stick with plain JS to build out your evolution chain... try giving this a go, it was based on your angular for loop. This should leave you with an array (evoChain) of the objects containing the data you are looking for ordered from first evolution at 0 index to last evolution at the last index.
var evoChain = [];
var evoData = response.data.chain;
do {
var evoDetails = evoData['evolution_details'][0];
evoChain.push({
"species_name": evoData.species.name,
"min_level": !evoDetails ? 1 : evoDetails.min_level,
"trigger_name": !evoDetails ? null : evoDetails.trigger.name,
"item": !evoDetails ? null : evoDetails.item
});
evoData = evoData['evolves_to'][0];
} while (!!evoData && evoData.hasOwnProperty('evolves_to'));
In your sample case above the resulting array should appear as follows:
[{
"species_name": "charmander",
"min_level": 1,
"trigger_name": null,
"item": null
}, {
"species_name": "charmeleon",
"min_level": 16,
"trigger_name": "level-up",
"item": null
}, {
"species_name": "charizard",
"min_level": 36,
"trigger_name": "level-up",
"item": null
}]
The approved answer above does not work if there are multiple evolutions such as Eevee or Snorunt. That will only return the first evolution e.g. Vaporeon
The following checks number of evolutions and runs through them all.
let evoChain = [];
let evoData = chain.chain;
do {
let numberOfEvolutions = evoData['evolves_to'].length;
evoChain.push({
"species_name": evoData .species.name,
"min_level": !evoData ? 1 : evoData .min_level,
"trigger_name": !evoData ? null : evoData .trigger.name,
"item": !evoData ? null : evoData .item
});
if(numberOfEvolutions > 1) {
for (let i = 1;i < numberOfEvolutions; i++) {
evoChain.push({
"species_name": evoData.evolves_to[i].species.name,
"min_level": !evoData.evolves_to[i]? 1 : evoData.evolves_to[i].min_level,
"trigger_name": !evoData.evolves_to[i]? null : evoData.evolves_to[i].trigger.name,
"item": !evoData.evolves_to[i]? null : evoData.evolves_to[i].item
});
}
}
evoData = evoData['evolves_to'][0];
} while (!!evoData && evoData.hasOwnProperty('evolves_to'));
return evoChain;
brandudno is correct: the extra if(numberOfEvolutions) is the more complete approach (THANKS #brandudno! This really helped me solve for ALL the use cases - including eevee!)
I like the use of !!evoData in the while statement now that I took the time to understand it, but it was confusing for me at 1st, so I made a minor modification that still works and may be easier for other new developers (continues until evoData becomes undefined).
Lastly, I made a minor change in case others also prefer to use the . annotation (evoData.evolves_tovs.evoData['evolves_to']`) to take advantage of autocomplete, etc.
let evoChain = [];
let evoData = chain.chain;
do {
let numberOfEvolutions = evoData.evolves_to.length;
evoChain.push({
"species_name": evoData .species.name,
"min_level": !evoData ? 1 : evoData .min_level,
"trigger_name": !evoData ? null : evoData .trigger.name,
"item": !evoData ? null : evoData .item
});
if(numberOfEvolutions > 1) {
for (let i = 1;i < numberOfEvolutions; i++) {
evoChain.push({
"species_name": evoData.evolves_to[i].species.name,
"min_level": !evoData.evolves_to[i]? 1 : evoData.evolves_to[i].min_level,
"trigger_name": !evoData.evolves_to[i]? null : evoData.evolves_to[i].trigger.name,
"item": !evoData.evolves_to[i]? null : evoData.evolves_to[i].item
});
}
}
evoData = evoData.evolves_to[0];
} while (evoData != undefined && evoData.hasOwnProperty('evolves_to'));
return evoChain;
I am using a recursive function to solve this.
Here's how it goes with plain JavaScript.
let evoChain = [];
function getEvo(arr) {
if (arr[0].evolves_to.length > 0) {
evoChain.push(arr[0].species.name);
getEvo(arr[0].evolves_to);
} else {
evoChain.push(arr[0].species.name);
return 0;
}
}
getEvo([data.chain]);```
The essence is that I have json file:
[
{
"id": 0,
"username": "Antony",
"users": [
{
"id": 1,
"like": 0
},
{
"id": 2,
"like": 1
},
{
"id": 3,
"like": 0
},
{
"id": 4,
"like": 1
}
]
},
{
"id": 1,
"username": "Janet",
"users": [
{
"id": 0,
"like": 0
},
{
"id": 2,
"like": 1
},
{
"id": 3,
"like": 1
},
{
"id": 4,
"like": 1
}
]
},.......
I need to count how many "likes", have each user.
ie:
For example, take the first id == 0.
We pass on the object, which can be very much and look:
If id == 0 and like == 1, add 1 to the array.
In the end, I must have:
usersWithLikes [id User] = number of likes for all objects
For example:
usersWithLikes [0] = 3
usersWithLikes [1] = 1
usersWithLikes [2] = 4
usersWithLikes [3] = 0
At the moment, I think so:
thumbsUp_data - json data
var usersWithLikes = thumbsUp_data.map(function(user_data){
return user_data.users.filter(function(value){
return value.like == 1;
}).length;
});
But this is not correct, because it considers how many likes the object.
Help with the decision ...
Filter out the user object, grab the first element of the returned array and then filter on that object's user array for like === 1 returning it's length;
function howManyLikes(id) {
return arr.filter(function (user) {
return user.id === id;
})[0].users.filter(function (el) {
return el.like === 1;
}).length;
}
howManyLikes(1); // 3
DEMO
thumbsUp_data.forEach(function(data) {
data.users.forEach(function(value) {
usersWithLikes[value.id] = usersWithLikes[value.id] || 0;
usersWithLikes[value.id] += value.like;
});
});
Thats all, it's a solution!