brand new to Javascript.
I have figured out how to get data back from a Monday.com board, and it is returned as a JSON value like this:
{
"boards": [
{
"items": [
{
"column_values": [
{
"id": "location",
"title": "Location",
"type": "location",
"text": "Cape Town, South Africa"
}
]
},
{
"column_values": [
{
"id": "location",
"title": "Location",
"type": "location",
"text": "Paris, France"
}
]
},
{
"column_values": [
{
"id": "location",
"title": "Location",
"type": "location",
"text": "New York, NY, USA"
}
]
}
]
}
]
}
There are 3 items here, but this amount can be anything.
I need to get the location text (e.g. "Cape Town, South Africa") and then I need to use this later in an API call to get the weather of this location.
I finally managed to display in the console the location, like this:
console.log(JSON.stringify(this.state.boardData.boards[0].items[0].column_values[0].text));
Obviously this then displays what I want, but only the value of the first item.
I need to do this dynamically to get all the locations, and I need to store this into variables, so that I can then make an API call to get the weather of each of the 3 (or more) locations.
I am totally lost and have been struggling for hours. Once I manage to do this, I still have no idea how I'll make the API call but one thing at a time :)
Another approach:
const rawData = {boards:[{items:[{column_values:[{id:"location",title:"Location",type:"location",text:"Cape Town, South Africa"}]},{column_values:[{id:"location",title:"Location",type:"location",text:"Paris, France"}]},{column_values:[{id:"location",title:"Location",type:"location",text:"New York, NY, USA"}]}]}]};
const locations = [];
for (const board of rawData.boards) {
for (const item of board.items) {
for (const value of item.column_values) {
locations.push(value.text);
}
}
}
console.log(locations);
You can extract the text with some amount of nested .map. Map boards => map items => map column_values. You will get an array of arrays of arrays. And then you can apply .flat() to unwrap them all. (.flat(Infinity); also can be used)
const apiData={boards:[{items:[{column_values:[{id:"location",title:"Location",type:"location",text:"Cape Town, South Africa"}]},{column_values:[{id:"location",title:"Location",type:"location",text:"Paris, France"}]},{column_values:[{id:"location",title:"Location",type:"location",text:"New York, NY, USA"}]}]}]};
const locations = apiData.boards
.map((board) => board.items.map((i) => i.column_values.map((cv) => cv.text)))
.flat(2);
console.log(locations);
So in javascript we have an array function map, using which we can iterate over array that can be used here. It would look something like this:
let arr = boards[0].items.map(element => element.column_values[0].text)
and this arr will contain the list of all the city names, which you can further use to send the data to api.
(Edit: considering column_values to be array with one element only and items can have multiple elements)
Related
I'm creating a query but i came a section when i don't have idea that how do it. I have one array that have for example two items
//filter array
const filterArray=r.expr(['parking', 'pool'])
and also i have one table with follows records:
[
{
"properties": {
"facilities": [
"parking"
],
"name": "Suba"
}
},
{
"properties": {
"facilities": [
"parking",
"pool",
"pet friendly"
],
"name": "Kennedy",
}
},
{
"properties": {
"facilities": [
"parking",
"pool"
],
"name": "Soacha"
}
},
{
"properties": {
"facilities": [
"parking",
"pet friendly",
"GYM"
],
"name": "Sta Librada"
}
},
]
I need filter the records with the array but i need that record has all items of array filter. If the record has more item of array filter not is problem, i need if contains all items of array filter get that record. On this case I need all records that have the facilities "pool" and "parking"
Current query
Current query but it also return records with one or two items of the filter array
r.db('aucroom').table('hosts')
.filter(host=>
host('properties')('facilities').contains(val=>{
return filterArray.contains(val2=>val2.eq(val))
})
)
.orderBy('properties')
.pluck(['properties'])
results that I desire wait
Like the image example:
If you want a strict match of two arrays (same number of elements, same order), then use .eq()
array1.eq(array2)
If you want the first array to contain all elements of the second array, then use .setIntersection(), just note array2 should contain distinct elements (a set):
array1.setIntersection(array2).eq(array2)
We have a situation that can be best described in terms of an analogy. Let us assume that we have a mapping between name and city+state+zipcode. Here the name is guaranteed to be unique. Our sample data (adapted from here) is as follows:
James Butt: New Orleans LA 70116
Josephine Darakjy: Brighton MI 48116
Art Venere: Bridgeport NJ 8014
Lenna Paprocki: Anchorage AK 99501
Donette Foller: Hamilton OH 45011
Simona Morasca: Ashland OH 44805
Mitsue Tollner: Chicago IL 60632
Leota Dilliard: San Jose CA 95111
Sage Wieser: Sioux Falls SD 57105
Kris Marrier: Baltimore MD 21224
What would be a good JSON structure in this case? We are looking for something that is more efficient, from a processing perspective, for JavaScript. We see at least two options.
Option 1
{
"James Butt": "New Orleans LA 70116",
"Josephine Darakjy": "Brighton MI 48116",
"Art Venere": "Bridgeport NJ 8014",
"Lenna Paprocki": "Anchorage AK 99501",
"Donette Foller": "Hamilton OH 45011",
"Simona Morasca": "Ashland OH 44805",
"Mitsue Tollner": "Chicago IL 60632",
"Leota Dilliard": "San Jose CA 95111",
"Sage Wieser": "Sioux Falls SD 57105",
"Kris Marrier": "Baltimore MD 21224"
}
Option 2
[
{
"name": "James Butt",
"address": "New Orleans LA 70116"
},
{
"name": "Josephine Darakjy",
"address": "Brighton MI 48116"
},
{
"name": "Art Venere",
"address": "Bridgeport NJ 8014"
},
{
"name": "Lenna Paprocki",
"address": "Anchorage AK 99501"
},
{
"name": "Donette Foller",
"address": "Hamilton OH 45011"
},
{
"name": "Simona Morasca",
"address": "Ashland OH 44805"
},
{
"name": "Mitsue Tollner",
"address": "Chicago IL 60632"
},
{
"name": "Leota Dilliard",
"address": "San Jose CA 95111"
},
{
"name": "Sage Wieser",
"address": "Sioux Falls SD 57105"
},
{
"name": "Kris Marrier",
"address": "Baltimore MD 21224"
}
]
Option 1:
This is a bad idea even if you are completely certain there are no duplicate names. Firstly, there is no real-world situation in which there are no duplicate names. Secondly, what if the name contains a special character?
Option 2:
This is the right way to format the data, except as noted in the comments there should also be a unique ID field mapped to each name.
const data = [
{
"id": 1,
"name": "James Butt",
"address": "New Orleans LA 70116"
},
...
];
user = data.filter(({id})=>id==1); //gives you this user
user = data.filter(({name})=>name=='James Butt'); //also works
The reason to add the unique ID inside the data construct is to avoid relying on the order these are inserted into the data array. Any data coming from a real world database will always have some sort of unique ID field, which may be numeric or alphanumeric. But the order in which that data is returned will not be a reliable indicator of what the true id of the user is.
Not sure what you really mean by "processing efficiency", but guessing you would like to efficiently look up people addresses by their names. The proposed solutions require iterating over entire collection, so they'll work on 500 records and won't on 1M.
Also, as other people have mentioned, name collisions are real (especially when you get that 1M records set), so assuming you need two features from your data structure:
efficient address lookups by name;
no name collisions.
This means you need a multimap where keys are people names and values are sets of addresses. Basically, your first option with arrays of addresses as field values. Alternatively, you can use a Map for more efficient additions/removals and easier access to the number of records (unique people names) stored.
Maps (and Sets) in V8 implementation are said to have O(1) time complexity vs the linear time when using arrays. So they're efficient.
Speaking of efficiency (and to prevent duplicated name-key clash)
I'd map the string-data into an Object where keys are Unique IDs (just like in a database):
{
7 : {
"id": 7,
"name": "James Butt",
"address": "New Orleans LA 70116"
},
19 : {
"id": 19,
"name": "Josephine Darakjy",
"address": "Brighton MI 48116"
}
}
Extracting a single record:
We gain the speed by immediately extracting a record given a key ID just like a lookup for a memory address - instead of always iterating the (in the worst case - the entire) array in search for a single record.
Extracting Multiple records:
You can always iterate Objects using Object.keys(), Object.values() or Object.entries() - and loop, just like you would with Array.
Since from ES2015 object keys order is predictable, you can effortlessly have the Object ordered by ID out of the box - giving that by default the records are organized by creation-date - since DB rows IDs are incremental.
Example: Get record by ID or Value
const users = {
6 : {
"id": 6,
"name": "Antonette Darakjy",
"address": "Brighton MI 48116"
},
7 : {
"id": 7,
"name": "James Butt",
"address": "New Orleans LA 70116"
},
19 : {
"id": 19,
"name": "Josephine Darakjy",
"address": "Brighton MI 48116"
},
};
// GET BY ID
console.log(users[7]); // No need to iterate tens of thousands of records
// GET BY KEY VALUE
// Return an array of filtered users
const filterBy = (prop, val) => Object.values(users).filter(user => {
return user[prop] === val;
});
console.log(filterBy("address", "Brighton MI 48116"));
I am fetching some data via an API call (within my dataservicse.ts file) - and the response I get is a sort of complex JSON structure. I am able to fetch a specific part of the response as follows in my corresponding Component file as follows -
Here is one of the JSON object response that represents the general structure -
{
"address": {
"building": "1234",
"coord": [0, 0],
"street": "123 Main Street",
"zipcode": "00000"
},
"address2": "Test Suite 000",
"grades": [{
"grade": "A",
"score": 3
}, {
"grade": "B",
"score": 4
}, {
"grade": "A",
"score": 2
}],
"name": "John Doe",
"_id": "1212121"
}
Now - my goal is to acquire the 'name' attribute as well as the first 'grade' value within the grades attribute from each response object - and map them into separate Arrays so that I can display them in table columns using *ngFor.
This is my Component code
export class TestDataComponent implements OnInit {
name$: Object;
grade$: Object;
constructor(private data: DataService, private data2: DataService) { }
ngOnInit() {
//getAPIData is returning the API response from the dataservices.ts file
this.data.getAPIData().subscribe(
data=>console.log(data.response.map(name=>name.name))
); //this works fine - I get the names in an array
this.data2.getAPIData().subscribe(
data2=>console.log((data2.response.map(grade=>grade.grades)).map(grades
=> {grades.map((value, index) => value.grade})) //this returns an undefined value
);
}
Now - if I console.log((data2.response.map(grade=>grade.grades))
I get an Array of Array objects such as -
Array - [Array(3), Array(3), Array(2)]
and each of them consist of the 'grades' attribute Array of objects.
(taking the first array from above) -
Array(3)
0:{"grade": "A","score": 3}
1:{"grade": "B", "score": 4}
2:{"grade": "A", "score": 2}
Thus - I further map my initial response to achieve the 'grade' value. Also - I only want the first grade - thus I have a simple condition added as follows -
console.log((data2.response.map(grade=>grade.grades))
.map(grades
=> {grades.map((value, index) =>{if(index<1) value.grade})}))
As mentioned in the comment - I get an undefined value.
I undestand this issue may be fairly complex but I've tried my best to explain it as clearly as possible. My goal is to get the first 'grade' values from each object and display them in an Array - just as the names, so that I can use it to display it on a table.
I am fairly new to Angular6, just switching from Angular 1.6 - so I am pretty sure I am messing something up.
What would be the best way to get the grade values into an Array by nested mapping within subscribe? Or is there a better approach to the same ?
Also - for the sake of simplicity, ignore the fact that the first subscription is present (for the name attribute) - I showed it here so as to make it clear as to what I want to achieve.
Here is what I think you're asking for since you never gave a concrete example of what you're trying to map/reduce. Also, this is vanilla JavaScript but could easily be translated into RxJS.
// I am assuming that a call to `DataServce.getAPIData()` returns an array
const api_response = [{
"address": {
"building": "1234",
"coord": [0, 0],
"street": "123 Main Street",
"zipcode": "00000"
},
"address2": "Test Suite 000",
"grades": [{
"grade": "A",
"score": 3
}, {
"grade": "B",
"score": 4
}, {
"grade": "A",
"score": 2
}],
"name": "John Doe",
"_id": "1212121"
}];
// Map and pluck the values you need
const result = api_response.map(v => [v.name, v.grades[0].score])
// Or as an array of objects
const obj_result = result.map(([name, score]) => ({ name, score }))
// Is this what you want?
console.log('Array', result);
console.log('Objects', obj_result);
Quick Update
Thanks for accepting the answer. Just wanted to give a quick of what this might look like using RxJS. I say might because the code snippet below is untested.
this.nameAndScores$ = data.getAPIData().pipe(
map(({ response }) => response),
map(({ name, grades }) => ( { name, score: grades[0].score } ))
)
Assuming that nameAndScores$ is a property of your component instance, you can do *ngFor item in nameAndScores$ | async and avoid any explicit subscriptions in your code.
You are using curly braces with a fat arrow in second map function. While using curly braces, you should return a value using the return keyword.
I am working with JSON data in a JavaScript object like this:
var data = [
{ "City" : "New York", "State" : "New York" },
{ "City" : "Fargo", "State" : "North Dakota" },
{ "City" : "Los Angeles", "State" : "California" }
];
And I want to remove state data so it ends up like this:
var data = [
{ "City" : "New York"},
{ "City" : "Fargo"},
{ "City" : "Los Angeles"}
];
Currently I'm looping through and removing it but is there a way to remove the city from the object without having to loop through?
I found the "delete" operator ("The delete operator removes a property from an object.") but it seems to only work if there is just one item with that property, not globally as in the example object.
delete object["State"] //doesn't work
Edit: My bad. I copy/pasted and edited incorrectly. I have changed the original post to use correct format as supplied in Mr. Polywhirl's answer.
Edit: I ended up using the map method as suggested by mccainz. Using map allows for pulling all of a certain key/value pair (like city) from one array into another. You can also pull multiple like
newData = data
.map(function(v){
return {City:v.City, State:v.State};
});
It will work for my purposes and is better since I'm keeping the minority of the key/value pairs. However, it doesn't appear that there are any solutions for performing the task in the original question. For example, if you had 100 different key/value pairs per array item, you'd have to add 99 to a new array instead of being able to just remove one from the existing.
You should convert your data to an array of objects and simply operate on the array. The example below uses array.map to return an array with the State properties absent. However, there are numerous ways to skin this cat.
(edited to demonstrate a filtering preprocess before the map)
var data=[];
data.push({"City":"New York","State":"New York"});
data.push({"City":"Fargo","State":"North Dakota"});
data.push({"City":"Los Angeles","State":"California"});
var newData;
newData = data
.filter(function(v){
return v.State !=='California';
})
.map(function(v){
return {City:v.City};
});
Array.prototype.filter
Array.prototype.map
As others have indicated, you can't have duplicate properties in your JSON object. Your data is meant to be in an Array, not in one monster object.
If you don't want to modify the original object, you can combine map and reduce to create filtered objects.
var data = [
{ "City" : "New York", "State" : "New York" },
{ "City" : "Fargo", "State" : "North Dakota" },
{ "City" : "Los Angeles", "State" : "California" }
];
var filterKeys = function(data, keysToFilter) {
return data.map(function(item) {
return Object.keys(item).reduce(function(result, key) {
if (keysToFilter.indexOf(key) === -1) result[key] = item[key];
return result;
}, {});
});
}
document.body.innerHTML = JSON.stringify(filterKeys(data, ['State']), null, ' ');
body {
font-family: monospace;
white-space: pre;
}
Result
[
{ "City": "New York" },
{ "City": "Fargo" },
{ "City": "Los Angeles" }
]
you cant initiate an object with two identical keys.for example
var obj={city:"NEW YORK",city:"NEW JERSEY"}
city property will hold NEW JERSEY.because it's overwritten.
JSON.stringify(obj); // {"city":"NEW JERSEY"}
if you initiate an object with your json.your obj1 will hold only one city and state property.
JSON.stringify(obj1); //{"City":"Fargo","State":"North Dakota"}
How to refer to each property of an object in an array of objects in MongoDB MapReduce JavaScript query?
Here is my data:
{
"_id": ObjectId("544ae3de7a6025f0470041a7"),
"name": "Bundle 4",
"product_groups": [
{
"name": "camera group",
"products": [
{
"$ref": "products",
"$id": ObjectId("531a2fcd26718dbd3200002a"),
"$db": "thisDB"
},
{
"$ref": "products",
"$id": ObjectId("538baf7c26718d0a55000043"),
"$db": "thisDB"
},
{
"$ref": "products",
"$id": ObjectId("538baf7c26718d0a55000045"),
"$db": "thisDB"
}
]
},
{
"name": "lens group",
"products": [
{
"$ref": "products",
"$id": ObjectId("531e3ce926718d0d45000112"),
"$db": "thisDB"
},
{
"$ref": "products",
"$id": ObjectId("531e3ce926718d0d45000113"),
"$db": "thisDB"
}
]
}
]
}
Here is my map function: (for simplicity I took out the reduce option since it doesn't matter if the map doesn't work right)
var map = function() { emit(this.product_groups, this.product_groups.products); };
db.instant_rebates.mapReduce(
map,
{
out: "map_reduce_example",
query: {"_id": ObjectId("544ae3de7a6025f0470041a7")}
}
);
However the problem is that the "value" field in the result always comes up as "undefined". Why? Why doesn't this.product_groups.products return the products array? How do I fix this?
Also, I want it to do is to emit TWICE, once for each of the two product_groups. But so far it only emits ONCE. How do I fix that?
Under mapReduce operations the documents are presented as JavaScript objects so you need to treat them as such and traverse them. That means processing each member of the array:
var map = function() {
this.product_groups.forEach(function(group) {
emit( group.name, { products: group.products } );
});
};
var reduce = function(){};
db.instant_rebates.mapReduce(
map,
reduce,
{
out: "map_reduce_example",
query: {"_id": ObjectId("544ae3de7a6025f0470041a7")}
}
);
The requirements of the "emit" function is both a "key" and a "value" to be presented as arguments which are emitted. The "value" must be singular therefore to emit an "array" of data you need to wrap this under the property of an object. The "key" must be a singular value as it's intent to it be used as the "grouping key" in the reduce operation, and the "name" field should be sufficient at least for example.
Naturally since there is a top level array in the document you process "each element" as is done with the function, and then each result is "emitted" so there are "two" results emitted from this one document.
You also need to at least define a "reduce" function even if it never gets called because all of the emitted keys are different, as is the case here.
So, it's JavaScript. Treat a list structure as a list.
Please note. This is all your question is about. If you want to ask further questions on mapReduce then please ask other questions. Don't ask any more of this one. I don't want to talk about your field naming, or go into detail of how this seems to be working towards "how do I pull in data from the other collection", which is something you cannot do.