JS: Extracting data from an array of objects - javascript

I have a complex query with 100s of fields and nested fields. What I want to do is, for each Index, extract the English and French text. As you can see in the array, there is no French text for some indexes. In that case I want to get the English text.
For me extracting the English text works fine because the text is already there, but incase of French, I get undefined errors. What would be the best way to implement this. Is Loadash needed for this or just pure JS methods?
Just to be clear, I have erros with extracting french because in some fields, french text is not available, I want to use the english value in that case.
Also It is recommend if I am able to get the English and French values by it's language field rather than the index. I have no idea how to do that.
Any suggestion, documentation is appreciated. Thank you!
example array:
[
{
id: "1",
name: [
{
language: "en-US",
text: "HOLIDAY"
}
],
order: 6,
Groups: [
{
name: [
{
language: "en-US",
text: "REGULAR"
}
],
code: "REGEARN"
},
{
name: [
{
language: "en-US",
text: "CHARGE"
}
],
code: "CHARGE"
}
]
}
]
and here is the code sandbox that reproduces my error:
CODE SAND BOX
https://codesandbox.io/s/javascript-forked-5073j
EDIT:
EXPECTED OUTPUT:
{
key: key,
englishtext: "Value Here",
frenchtext: "Value Here"
}
below is a working code, but issue is it does not work when there is no french language or that field. I get undefined errors. So is it possible I can get the needed data from the language field?
x.map((y) => ({
key: y.id,
name: y.name[0].text,
groupname: y.Groups ? x.Groups[0].name?.[0].text : 'N/A',
}))

Do you expect result like this? If you don't mind lodash.
const _ = require('lodash');
const getNames = (arr) => {
return arr.map((obj) => {
const id = obj.id;
const englishtext = _.get(obj, 'name[0].text', 'N/A');
const frenchtext = _.get(obj, 'name[1].text', englishtext);
return { id, englishtext, frenchtext };
});
};
console.log(getNames(x));
// [
// { id: '1', englishtext: 'HOLIDAY', frenchtext: 'HOLIDAY' },
// { id: '2', englishtext: 'Stat Holiday', frenchtext: 'Congé Férié' },
// { id: '3', englishtext: 'Over', frenchtext: 'Over' }
// ]

Related

Using object as Vue Select options

I know, Vue Select docs specify that options should be an array, but is there a way around it? I want to use object keys as values and object values as labels.
My data:
obj: {
value: 'en',
options: {
'ar': 'Arabic',
'ast': 'Asturian',
'en':' English'
}
}
<v-select
v-model="obj.value"
:options="Object.keys(obj.options)"
>
I know i can use keys as options that way, but I have no idea how to use values as labels. Any tips?
There are multiple ways you could do that but one options is:
<v-select v-model="obj.value" :options="obj.options" :reduce="val => val.code"/>
Only change to your data should be that the obj.options should look like below:
obj: {
value: "en",
options: [
{ label: "Arabic", code: "ar" },
{ label: "Asturian", code: "ast" },
{ label: "English", code: "en" }
]
}
Relevant documentation transforming-selections

Why javascript array sort doesn't compare all elements with each other?

I'm trying to understand why Javascript array sort doesn't work with the following logic. I have no problems making my own algorithm to sort this array, but I'm trying to make it with the Javascript sort built-in method to understand it better.
In this code, I want to push entities that "belongs to" another entity to the bottom, so entities that "has" other entities appear on the top. But apparently, the sort method doesn't compare all elements with each other, so the logic doesn't work properly.
Am I doing something wrong, or it is the correct behavior for the Javascript sort method?
The code I'm trying to execute:
let entities = [
{
name: 'Permission2',
belongsTo: ['Role']
},
{
name: 'Another',
belongsTo: ['User']
},
{
name: 'User',
belongsTo: ['Role', 'Permission2']
},
{
name: 'Teste',
belongsTo: ['User']
},
{
name: 'Role',
belongsTo: ['Other']
},
{
name: 'Other',
belongsTo: []
},
{
name: 'Permission',
belongsTo: ['Role']
},
{
name: 'Test',
belongsTo: []
},
]
// Order needs to be Permission,
let sorted = entities.sort((first, second) => {
let firstBelongsToSecond = first.belongsTo.includes(second.name),
secondBelongsToFirst = second.belongsTo.includes(first.name)
if(firstBelongsToSecond) return 1
if(secondBelongsToFirst) return -1
return 0
})
console.log(sorted.map(item => item.name))
As you can see, "Role" needs to appear before "User", "Other" before "Role", etc, but it doesn't work.
Thanks for your help! Cheers
You're running into literally how sorting is supposed to work: sort compares two elements at a time, so let's just take some (virtual) pen and paper and write out what your code is supposed to do.
If we use the simplest array with just User and Role, things work fine, so let's reduce your entities to a three element array that doesn't do what you thought it was supposed to do:
let entities = [
{
name: 'User',
belongsTo: ['Role', 'Permission2']
},
{
name: 'Test',
belongsTo: []
},
{
name: 'Role',
belongsTo: ['Other']
}
]
This will yield {User, Test, Role} when sorted, because it should... so let's see why it should:
pick elements [0] and [1] from [user, test, role] for comparison
compare(user, test)
user does not belong to test
test does not belong to user
per your code: return 0, i.e. don't change the ordering
we slide the compare window over to [1] and [2]
compare(test, role)
test does not belong to role
role does not belong to test
per your code: return 0, i.e. don't change the ordering
we slide the compare window over to [2] and [3]
there is no [3], we're done
The sorted result is {user, test, role}, because nothing got reordered
So the "bug" is thinking that sort compares everything-to-everything: as User and Role are not adjacent elements, they will never get compared to each other. Only adjacent elements get compared.

Parsing PostgreSQL data into Highcharts chart objects correctly

I'm trying to fetch timeserie data from PostgreSQL & after successful queries and parsing of data, I have some problem in indexing it. This mistake is probably quite small, but I just cant find it.
After I get data from PostgreSQL, it looks like this:
[
{ id: 2,
time: 2019-09-12T03:36:04.433Z,
value: 0.311303124694538
},
{ id: 2,
time: 2019-09-12T03:36:03.434Z,
value: 0.13233108292117
},
{ id: 3,
time: 2019-09-12T03:36:03.434Z,
value: 0.13233108292117 }
]
After this step I'm reducing data by id:
let results = sqlresult.rows.reduce(function(results, row) {
(results[row.id] = results[row.id] || []).push([row.time,row.value]);
return results;
}, {})
let clonedObj = { ...results };
After this step data is formatted like in below:
{ '2':
[ [ 2019-09-12T03:36:04.433Z, 0.311303124694538 ],
[ 2019-09-12T03:36:03.434Z, 0.13233108292117 ],
[ 2019-09-12T03:36:02.432Z, 0.171794173529729 ]
]
}
But once I'm about to drop it into Highchart it won't work. My problem is probably that I didn't fully understand how does that reduce function work and now I'm trying to copy it. If some of you could show me how to avoid this step and to do all in data reduce step, I'd be thankful.
for(let i=0; i< Object.keys(clonedObj).length; i++){
highchart[i] = {
name: Object.keys(clonedObj)[i],
data: clonedObj[i]
}
}
I'm expecting result like this below:
[{"name":1,"data":[["2019-09-12T03:36:00.433Z",20],["2019-09-12T03:35:38.433Z",-20]]},{"name":2,"data":[["2019-09-12T03:36:04.433Z",0.311303124694538]}]]
From your nicely formatted data listings, it looks like you're using Postgres to package rows of data already. This is something I do all the time, but without some pretty narrow limits. I'd like to get better at this, so I figured I'd give your question a bit of time. To start with, I created a table named "reading" with your data:
CREATE TABLE IF NOT EXISTS reading (
id integer,
"time" text,
"value" real
);
I get back a listing like your top one with this query:
select array_to_json(array_agg(row_to_json(reading_row))) as reading_object
from (select id, time, value from reading) as reading_row
Your target output example doesn't parse right for me, I think you're after this:
[
{
"name":1,
"data":[
[
"2019-09-12T03:36:00.433Z",
20
],
[
"2019-09-12T03:35:38.433Z",
-20
]
]
},
{
"name":2,
"data":[
"2019-09-12T03:36:04.433Z",
0.311303124694538
]
}
]
Fair warning: Yeah, I don't really know how to do that, and I'm hoping someone answers with a simple script to generate exactly the format you want on the Postgres side. But I made a start. Check this out:
select id, json_object_agg(time, value order by time)
from reading
group by id
Here's what I get:
2 "{ ""2019-09-12T03:36:03.434Z"" : 0.132331, ""2019-09-12T03:36:04.433Z"" : 0.311303 }"
3 "{ ""2019-09-12T03:36:03.434Z"" : 0.132331 }"
Here's something that's...not right..but getting closer:
select array_to_json(array_agg(row_to_json(reading_row))) as reading_object
from (
select id, json_object_agg(time, value order by time) as data
from reading
group by id
) as reading_row
Which returns:
[
{
"id":2,
"data":{
"2019-09-12T03:36:03.434Z":0.132331,
"2019-09-12T03:36:04.433Z":0.311303
}
},
{
"id":3,
"data":{
"2019-09-12T03:36:03.434Z":0.132331
}
}
]
I took another crack at it here, this might be what you're after, or close. I noticed you're renaming 'id' as 'name', so that's in the final query:
select array_to_json(array_agg(row_to_json(subquery)))
from (
select id as name,
array_to_json(array_agg(json_build_object('time', time, 'value', value))) as data
from reading
group by id
) subquery
The output, pretty-printed, looks like this:
[
{
"name":2,
"data":[
{
"time":"2019-09-12T03:36:04.433Z",
"value":0.311303
},
{
"time":"2019-09-12T03:36:03.434Z",
"value":0.132331
}
]
},
{
"name":3,
"data":[
{
"time":"2019-09-12T03:36:03.434Z",
"value":0.132331
}
]
}
]
This variant has the same structure, but without labels on the elements within the array:
select array_to_json(array_agg(row_to_json(subquery)))
from (
select id as name,
array_to_json(array_agg(array[time, value::text])) as data
from reading
group by id
) subquery
Apart from the numeric value being cast as text, I think this is what you asked for:
select array_to_json(array_agg(row_to_json(subquery)))
from (
select id as name,
array_to_json(array_agg(array[time, value::text])) as data
from reading
group by id
) subquery
[
{
"name":2,
"data":[
[
"2019-09-12T03:36:04.433Z",
"0.311303"
],
[
"2019-09-12T03:36:03.434Z",
"0.132331"
]
]
},
{
"name":3,
"data":[
[
"2019-09-12T03:36:03.434Z",
"0.132331"
]
]
}
]
Note: I don't see where you're getting your output of 20, -20 in your example.
Between array_to_json(), row(), array_agg(), and json_build_object(), it looks like you can get most any format you need.
Here's hoping that someone who actually knows what they're doing chimes in.

How to parse specific object in angular or javascript?

How are we going to parse following type of object in angular or javascript, maybe using for search loop or parsing?
I wanted to get the title value and assign it to title because as you can see the value of title is object:
{'title': 'Hey', 'instruction': 'Take a sad song a…75, 'sub_title': 'Jude', 'timelimit': '01:05:01'}
instead of "Hey" as you can see on the example (same also with the second object). Is there a way we can do that?
JSON array of objects format:
[
{
id:0,
title:"{'title': 'Hey', 'instruction': 'Take a sad song a…75, 'sub_title': 'Jude', 'timelimit': '01:05:01'}"
},
{
id:1,
title:"{'title': 'Assessment', 'instruction': 'Jude', 'cr…71, 'sub_title': 'Test', 'timelimit': '06:25:08'}"
}
]
Desired output:
[
{
id:0,
title:"Hey"
},
{
id:1,
title:"Assessment"
}
]
Make sure your have the correct format in json - double quotation marks inside and single outside.
Like this
'{"title": "Hey", "instruction": "Take a sad song a…75", "sub_title": "Jude", "timelimit": "01:05:01"}'
Then you can simply do.
let jsonString = '{"title": "Hey", "instruction": "Take a sad song a…75", "sub_title": "Jude", "timelimit": "01:05:01"}';
let title = JSON.parse(jsonString).title;
console.log(title);
var jsonObj = [
{
id:0,
title:"{'title': 'Hey', 'instruction': 'Take a sad song a…75, 'sub_title': 'Jude', 'timelimit': '01:05:01'}"
},
{
id:1,
title:"{'title': 'Assessment', 'instruction': 'Jude', 'cr…71, 'sub_title': 'Test', 'timelimit': '06:25:08'}"
}
];
var updatedJsonObj = jsonObj.map( obj => {
return {
...obj,
title: JSON.parse(obj.title).title
}
});
console.log(updatedJsonObj);
//updatedJsonObj will have your required format
Here we are doing following steps
Iterate over array
For each object, title field is not valid JSON. make it valid by using title.replace(/'/g, '"'). Then Parse JSON.
Then assign title of parsed JSON to title of object
Here is the code
arr = [
{
id:0,
title:"{'title': 'Hey', 'instruction': 'Take a sad song a…75', 'sub_title': 'Jude', 'timelimit': '01:05:01'}"
},
{
id:1,
title:"{'title': 'Assessment', 'instruction': 'Jude', 'sub_title': 'Test', 'timelimit': '06:25:08'}"
}
]
arr = arr.map((e)=> { e.title = JSON.parse(e.title.replace(/'/g, '"')).title; return e; })
// expected result is in arr
.
As others have stated your json is not valid but since you have mentioned that it is what you get from your backend and you cannot change it, I suggest treat your title as string and use string operations to get the desired value.
for example you can use the following to get ID and title
<div ng-repeat="item in data">
{{item.id}} -
{{item.title.split('\'')[3]}}
</div>
Demo

Complex Mongo query, checking simultaneously on several attributes

Here is what my database could look like :
[
{
_id : xxx,
languages : [
{ lang: "French", level: 1 },
{ lang: "English", level: 3 },
{ lang: "Spanish", level: 4 }
]
},
{
_id : yyy,
languages : [
{ lang: "French", level: 5 },
{ lang: "English", level: 2 }
]
}
]
I have that kind of list :
[
{
lang : "French",
cmp : "at least",
level : 3
},
{
lang : "English",
cmp : "at most",
level : 2
}
]
My goal is to build a query that, with this example :
Select all the users who speaks French with a level >=
AND who speaks English with a level <= 2
the selected users can have others languages for which I do not care
In other words, I want to build a query that finds every users who have ALL the languages specified in the list, each languages having to match the level comparison to be valid.
It's kinda hard, as I'm not used to such complex queries in MongoDB.
Currently, I'm not looking for level comparison. I just query for the users matching the good languages, no matter the level, using "profile.languages.lang" : { $all: languagesArray }, with languagesArray a list of strings I get with a .map on my comparison's object list.
My problem is that I don't know how to spevify so much constraints on a single attribute / list of my document. Of course, I could fetch to refine my search, but it would be really costly over time, as my database is growing pretty fast.
Could anyone guide me ?
Thanks.
Users.find({
$or: [
{
languages: {
$elemMatch: {
lang: 'French',
level: { $gte: 2 }
},
}
},
{
languages: {
$elemMatch: {
lang: 'English',
level: { $lte: 2 }
}
}
}
]
}).fetch();

Categories