Display data in consistent format for array of documents - javascript

I have a collection personemail with array of documents
{ "Name" : "A", "Email" : [ { "EmailAddress" : "a#home.com", "EmailType" : "Home" }, { "EmailAddress" : "a#work.com", "EmailType" : "Work" } ] }
{ "Name" : "B", "Email" : [ { "EmailAddress" : "b#work.com", "EmailType" : "Work" } ] }
{ "Name" : "C" }
I have to display data in below format, ie if we a person is not having home / work address , it should be displayed as "No data" if home or work email is not available preferably in same order (Home email first , Work email second)
{ "Name" : "A", "Email" : [ { "EmailAddress" : "a#home.com", "EmailType" : "Home" }, { "EmailAddress" : "a#work.com", "EmailType" : "Work" } ] }
{ "Name" : "B", "Email" : [ { "EmailAddress" : "No Data", "EmailType" : "Home" }, { "EmailAddress" : "b#work.com", "EmailType" : "Work" } ] }
{ "Name" : "C", "Email" : [ { "EmailAddress" : "No Data", "EmailType" : "Home" }, { "EmailAddress" : "No Data", "EmailType" : "Work" } ] }
I thought of implementing this with $unwind or $switch function . Suggestions please

It's possible:
db.collection.aggregate([
{ "$project": {
"Name": 1,
"Email": {
"$map": {
"input": ["Home", "Work"],
"as": "m",
"in": {
"$ifNull": [
{ "$arrayElemAt": [
{ "$filter": {
"input": "$Email",
"as": "e",
"cond": { "$eq": [ "$$e.EmailType", "$$m" ] }
}},
0
]},
{ "EmailAddress": "No Data", "EmailType": "$$m" }
]
}
}
}
}}
])
Which produces:
{
"_id" : ObjectId("591e7d66cb1a9433dab779cc"),
"Name" : "A",
"Email" : [
{
"EmailAddress" : "a#home.com",
"EmailType" : "Home"
},
{
"EmailAddress" : "a#work.com",
"EmailType" : "Work"
}
]
}
{
"_id" : ObjectId("591e7d66cb1a9433dab779cd"),
"Name" : "B",
"Email" : [
{
"EmailAddress" : "No Data",
"EmailType" : "Home"
},
{
"EmailAddress" : "b#work.com",
"EmailType" : "Work"
}
]
}
{
"_id" : ObjectId("591e7d66cb1a9433dab779ce"),
"Name" : "C",
"Email" : [
{
"EmailAddress" : "No Data",
"EmailType" : "Home"
},
{
"EmailAddress" : "No Data",
"EmailType" : "Work"
}
]
}
But personally I'd do that transformation in client code, since it's less obtuse. As a quick shell example:
db.collection.find().forEach(doc => {
doc.Email = ["Home", "Work"].map( m => {
if (!doc.hasOwnProperty('Email'))
doc.Email = [];
var val = doc.Email.filter(e => e.EmailType === m)[0];
return (val == null) ? { "EmailAddress": "No Data", "EmailType": m }
: val;
});
printjson(doc);
})
Basically though you use your "uniform" array of "Home" and "Work" as a source to $map, then lookup the elements in the documents current Email array. anything that returned a null on the lookup is swapped with the default data.

Related

Need to remove duplication in array of objects and merge array with union USING JS

Need to remove duplication in array of objects and merge array with union USING JS.
trying to filter array
Just wanted to merge array["INTERFACE"] on the basis of APP_ID. and remove duplicate records.
unfiltered unmerged array!
var data = [
{
"APP_ID" : "1001",
"INTERFACE" : [
{
"INTERFACE_ID" : "01",
"NAME" : "CIF OPENNING",
"URL" : "/CusIdInfo",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "06",
"NAME" : "SUMMARY COPC",
"URL" : "/SummaryCopc",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1002",
"INTERFACE" : [
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "08",
"NAME" : "BIOMETRIC",
"URL" : "/Biometric",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1001",
"INTERFACE" : [
{
"INTERFACE_ID" : "01",
"NAME" : "CIF OPENNING",
"URL" : "/CusIdInfo",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "05",
"NAME" : "SUMMARY",
"URL" : "/Summary",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "06",
"NAME" : "SUMMARY COPC 2",
"URL" : "/SummaryCopc2",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD 2",
"URL" : "/Dashboard 2",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1002",
"INTERFACE" : [
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "08",
"NAME" : "BIOMETRIC",
"URL" : "/Biometric",
"STATUS" : "A"
}
]
}
];
wanted result
[
{
"APP_ID" : "1002",
"INTERFACE" : [
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "08",
"NAME" : "BIOMETRIC",
"URL" : "/Biometric",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1001",
"INTERFACE" : [
{
"INTERFACE_ID" : "01",
"NAME" : "CIF OPENNING",
"URL" : "/CusIdInfo",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "05",
"NAME" : "SUMMARY",
"URL" : "/Summary",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "06",
"NAME" : "SUMMARY COPC",
"URL" : "/SummaryCopc",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
}, {
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD 2",
"URL" : "/Dashboard2",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "06",
"NAME" : "SUMMARY COPC 2",
"URL" : "/SummaryCopc2",
"STATUS" : "A"
}
]
}
]
trying to filter array
Just wanted to merge array["INTERFACE"] on the basis of APP_ID. and remove duplicate records.
Here is a slightly elastic solution relying on function generators that allows dynamic aggregation.
The logic followed by the below example is that in your data input, the unique key of the main objects is APP_ID. Next, the aggregation rule of each APP_ID is that it should follow another aggregation rule for INTERFACE. Each interface, in fact, has a unique NAME, explaining why you have multiple "07" and "06" in your result sample.
The code explanation is documented in the code itself.
var data = [
{
"APP_ID" : "1001",
"INTERFACE" : [
{
"INTERFACE_ID" : "01",
"NAME" : "CIF OPENNING",
"URL" : "/CusIdInfo",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "06",
"NAME" : "SUMMARY COPC",
"URL" : "/SummaryCopc",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1002",
"INTERFACE" : [
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "08",
"NAME" : "BIOMETRIC",
"URL" : "/Biometric",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1001",
"INTERFACE" : [
{
"INTERFACE_ID" : "01",
"NAME" : "CIF OPENNING",
"URL" : "/CusIdInfo",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "05",
"NAME" : "SUMMARY",
"URL" : "/Summary",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "06",
"NAME" : "SUMMARY COPC 2",
"URL" : "/SummaryCopc2",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD 2",
"URL" : "/Dashboard 2",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1002",
"INTERFACE" : [
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "08",
"NAME" : "BIOMETRIC",
"URL" : "/Biometric",
"STATUS" : "A"
}
]
}
];
// Aggregate duplicates with a common uniqueKey, invoking the aggregateExpression callback for each pair.
function* aggregateDuplicates(arr, uniqueKey, aggregateExpression) {
const aggregateGroups = arr.reduce((acc,next) => {
acc[next[uniqueKey]] = acc[next[uniqueKey]] || [];
return acc[next[uniqueKey]].push(next), acc;
}, {});
// loop items.
for (var [_, entries] of Object.entries(aggregateGroups)) {
// Aggregate results following the aggregateExpression.
yield Object.assign({}, entries.reduce((acc, next) => aggregateExpression(acc, next)));
}
}
// Aggregate duplicates of data, whose unique key is APP_ID.
const res = [...aggregateDuplicates(data, 'APP_ID', (a,b) => {
// In order to properly aggregate the INTERFACE property, acquire the set of entires interfaces of two items with the same APP_ID.
var interfacesSet = [...a.INTERFACE, ...b.INTERFACE];
// Finally, spread common values between them, then aggregate the INTERFACE property by its unique NAME key.
return Object.assign(a, b, {
INTERFACE: [...aggregateDuplicates(interfacesSet, 'NAME', (c,d) => {
// For that NAME property, just assign the values of both objects, nothing more nothing less.
return Object.assign(c,d)
})]
});
})];
console.log(res);
SIDE NOTE: The sorting to the INTERFACE property is not applied, this is a plus, but I don't think it's mandatory as long as the output data is effectively correct.
// Create the array of APP_ID
let idArr = data.map(val => val.APP_ID)
// Remove duplicate APP_ID
idArr = [...new Set(idArr)];
// Filter data according to unique APP_IDs
let newArr = idArr.map(val => {
return data.filter(value => value.APP_ID == val)[0]
})
console.log(newArr);
Solution
Here is a quick solution that I was able to come up with,
Note that this solution takes care of union of INTERFACES within the same APP_ID
const data = [
{
APP_ID: '1001',
INTERFACE: [
{
INTERFACE_ID: '01',
NAME: 'CIF OPENNING',
URL: '/CusIdInfo',
STATUS: 'A',
},
{
INTERFACE_ID: '07',
NAME: 'DASHBOARD',
URL: '/Dashboard',
STATUS: 'A',
},
{
INTERFACE_ID: '06',
NAME: 'SUMMARY COPC',
URL: '/SummaryCopc',
STATUS: 'A',
},
],
},
{
APP_ID: '1002',
INTERFACE: [
{
INTERFACE_ID: '07',
NAME: 'DASHBOARD',
URL: '/Dashboard',
STATUS: 'A',
},
{
INTERFACE_ID: '08',
NAME: 'BIOMETRIC',
URL: '/Biometric',
STATUS: 'A',
},
],
},
{
APP_ID: '1001',
INTERFACE: [
{
INTERFACE_ID: '01',
NAME: 'CIF OPENNING',
URL: '/CusIdInfo',
STATUS: 'A',
},
{
INTERFACE_ID: '05',
NAME: 'SUMMARY',
URL: '/Summary',
STATUS: 'A',
},
{
INTERFACE_ID: '06',
NAME: 'SUMMARY COPC 2',
URL: '/SummaryCopc2',
STATUS: 'A',
},
{
INTERFACE_ID: '07',
NAME: 'DASHBOARD 2',
URL: '/Dashboard 2',
STATUS: 'A',
},
],
},
{
APP_ID: '1002',
INTERFACE: [
{
INTERFACE_ID: '07',
NAME: 'DASHBOARD',
URL: '/Dashboard',
STATUS: 'A',
},
{
INTERFACE_ID: '08',
NAME: 'BIOMETRIC',
URL: '/Biometric',
STATUS: 'A',
},
],
},
];
const result = {};
data.forEach(elem => {
if (!result[elem.APP_ID]) {
result[elem.APP_ID] = {};
result[elem.APP_ID].APP_ID = elem.APP_ID;
result[elem.APP_ID].INTERFACE = elem.INTERFACE;
} else {
const interfaces = result[elem.APP_ID].INTERFACE;
for (const elemInterface of elem.INTERFACE) {
if (
!interfaces.some(inter => {
return elemInterface.INTERFACE_ID === inter.INTERFACE_ID;
})
) {
interfaces.push(elemInterface);
}
}
}
});
console.log('TCL: results', Object.values(result));
Assumptions:
Since you stated that you wanted union of the interfaces within the same APP_ID I assume that there should be no duplicate interfaces
Example: If there is an interface array A1,
[
{
INTERFACE_ID: '01',
NAME: 'CIF OPENNING',
URL: '/CusIdInfo',
STATUS: 'A',
},
{
INTERFACE_ID: '07',
NAME: 'DASHBOARD',
URL: '/Dashboard',
STATUS: 'A',
},
{
INTERFACE_ID: '06',
NAME: 'SUMMARY COPC',
URL: '/SummaryCopc',
STATUS: 'A',
},
]
and another interface array A2,
[
{
INTERFACE_ID: '01',
NAME: 'CIF OPENNING',
URL: '/CusIdInfo',
STATUS: 'A',
},
{
INTERFACE_ID: '05',
NAME: 'SUMMARY',
URL: '/Summary',
STATUS: 'A',
},
{
INTERFACE_ID: '06',
NAME: 'SUMMARY COPC 2',
URL: '/SummaryCopc2',
STATUS: 'A',
},
{
INTERFACE_ID: '07',
NAME: 'DASHBOARD 2',
URL: '/Dashboard 2',
STATUS: 'A',
},
]
Then A1 union A2 would be,
[
{
"INTERFACE_ID": "01",
"NAME": "CIF OPENNING",
"URL": "/CusIdInfo",
"STATUS": "A"
},
{
"INTERFACE_ID": "07",
"NAME": "DASHBOARD",
"URL": "/Dashboard",
"STATUS": "A"
},
{
"INTERFACE_ID": "06",
"NAME": "SUMMARY COPC",
"URL": "/SummaryCopc",
"STATUS": "A"
},
{
"INTERFACE_ID": "05",
"NAME": "SUMMARY",
"URL": "/Summary",
"STATUS": "A"
}
]
Note that there are no duplicates.
My second assumption is that when you check for duplicity in interfaces you use the INTERFACE_ID and not the whole interface object.
Example: Assume an interface object I1,
{
INTERFACE_ID: '01',
NAME: 'CIF OPENNING',
URL: '/CusIdInfo',
STATUS: 'A',
}
and another interface object I2 with the only difference being that it has a different status value which is 'B',
{
INTERFACE_ID: '01',
NAME: 'CIF OPENNING',
URL: '/CusIdInfo',
STATUS: 'B',
}
I am still considering I1 and I2 to be duplicates based on their INTERFACE_ID.
Suppose you want to compare entire object for duplicity then update your question and I shall change the answer to factor it in
Came up with this solution. Hope this works for you.
NOTE : In the expected result array you have 2 interface objects with same ID so i am assuming that two interface are duplicate only if all their properties match.
var data = [
{
"APP_ID" : "1001",
"INTERFACE" : [
{
"INTERFACE_ID" : "01",
"NAME" : "CIF OPENNING",
"URL" : "/CusIdInfo",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "06",
"NAME" : "SUMMARY COPC",
"URL" : "/SummaryCopc",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1002",
"INTERFACE" : [
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "08",
"NAME" : "BIOMETRIC",
"URL" : "/Biometric",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1001",
"INTERFACE" : [
{
"INTERFACE_ID" : "01",
"NAME" : "CIF OPENNING",
"URL" : "/CusIdInfo",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "05",
"NAME" : "SUMMARY",
"URL" : "/Summary",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "06",
"NAME" : "SUMMARY COPC 2",
"URL" : "/SummaryCopc2",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD 2",
"URL" : "/Dashboard 2",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1002",
"INTERFACE" : [
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "08",
"NAME" : "BIOMETRIC",
"URL" : "/Biometric",
"STATUS" : "A"
}
]
}
];
isInterfaceDuplicate = function(interface, app_id) {
var keys = Object.keys(interface);
var isDuplicate = false;
app_map[app_id].forEach(app_obj => {
var matched = true;
keys.forEach(key => {
if (interface[key] !== app_obj[key]) {
matched = false;
return;
}
});
if (matched) {
isDuplicate = true;
return;
}
});
return isDuplicate;
};
/* Create a mapping for APP_ID and INTERFACE */
var app_map = {};
data.forEach(app_obj => {
// If APP_ID is not present in map, then add in map directly.
if (!app_map[app_obj.APP_ID]) {
app_map[app_obj.APP_ID] = [...app_obj.INTERFACE];
return;
}
// If APP_ID is present in map, only add non duplicate interfaces in APP_ID key.
app_obj.INTERFACE.forEach(interface => {
var isDuplicate = isInterfaceDuplicate(interface, app_obj.APP_ID);
if (!isDuplicate) {
app_map[app_obj.APP_ID].push({...interface});
}
});
});
/* Create result array from the map */
var result = [];
Object.keys(app_map).forEach(app_id => {
result.push({
"APP_ID": app_id,
"INTERFACE": app_map[app_id]
});
});
console.log(result);

Create Functionality in Context Menu of jsTree not working

New nodes won't be created when 'types' plugin is defined.
Please look at this fiddle.
I'm unable to create new Nodes in the tree.
http://jsfiddle.net/z8L5r9w3/1/
$('#jstree').jstree({
"core" : {
"check_callback" : true,
"data" : [
{ "text" : "Branch 1", "type" : "branch", "children" : [
{ "text" : "leaf 1.1", "type" : "leaf" },
{ "text" : "leaf 1.2", "type" : "leaf" },
{ "text" : "leaf 1.3", "type" : "leaf" }
]
},
{ "text" : "Branch 2", "type" : "branch", "children" : [
{ "text" : "leaf 2.1", "type" : "leaf" },
{ "text" : "leaf 2.2", "type" : "leaf" },
{ "text" : "leaf 2.3", "type" : "leaf" }
]
}
]
},
"types" : {
"#" : {
"valid_children" : ["branch"]
},
"branch" : {
"valid_children" : ["leaf"]
},
"leaf" : {
"valid_children" : []
}
},
"plugins" : ["types", "dnd", "contextmenu"]});
Also, you can override "contextmenu"
"contextmenu":{
"items": function () {
return {
"Create": {
"label": "Create",
"action": function (data) {
var ref = $.jstree.reference(data.reference);
sel = ref.get_selected();
if(!sel.length) { return false; }
sel = sel[0];
type = ref.get_type(sel);
if (type == "#")
type = "branch";
else if (type == "branch")
type = "leaf";
else if (type == "leaf")
type = "";
sel = ref.create_node(sel, {text: "new "+type, type: type});
if(sel) {
ref.edit(sel);
}
}
},
"Rename": {
"label": "Rename",
"action": function (data) {
var inst = $.jstree.reference(data.reference);
obj = inst.get_node(data.reference);
inst.edit(obj);
}
},
"Delete": {
"label": "Delete",
"action": function (data) {
var ref = $.jstree.reference(data.reference),
sel = ref.get_selected();
if(!sel.length) { return false; }
ref.delete_node(sel);
}
}
};
}
},
You have a problem with "types". The "Create" action in the "contextmenu" does not know about the types of "branch" and "leaf" and create new node with "type" : "default".
You can see this:
"types" : {
"#" : {
"valid_children" : ["branch", "default"]
},
"branch" : {
"valid_children" : ["leaf", "default"]
},
"leaf" : {
"valid_children" : []
}
},

Join two collection in mongoDB and extract out data in node js

I am using MongoDB 3.6 for my project.
I have 2 collections "users" and "follow". I want to extract out details of user's followers and following (like an Instagram app).
users collection
{
"id" : "1",
"name" : "abc",
"age" : "26"
},
{
"id" : "2",
"name" : "xyz",
"age" : "22"
},
{
"id" : "3",
"name" : "qwe",
"age" : "23"
}
follow collection
{
"id" : "2",
"follow id" : "1"
},
{
"id" : "3",
"follow id" : "1"
},
{
"id" : "1",
"follow id" : "2"
},
{
"id" : "2",
"follow id" : "3"
},
{
"id" : "1",
"follow id" : "3"
}
Now i want following list of id 2 So id 2 is following id 1 and id 3
So, Output should be like this
{
"id" : "1",
"name" : "abc",
"age" : "26"
},
{
"id" : "3",
"name" : "qwe",
"age" : "23"
}
For that, I am using $lookup aggregation. But this is not giving the desired output which I want.
Here is my code -
Follow.aggregate([
{
$lookup:{
from:"users",
localField:"id",
foreignField:"id",
as:"fromItems"
}
},
{
$replaceRoot:{newRoot: {$mergeObjects: [ { $arrayElemAt: ["$fromItems", 0 ] }, "$$ROOT" ] } }
},
{ $project :
{
fromItems : 0
}
}
], callback)
For more understanding please refer the image
To get following list of id 2 you can use following query:
Follow.aggregate([
{
$match: { "id": "2" }
},
{
$lookup:{
from:"users",
localField:"follow id",
foreignField:"id",
as:"fromItems"
}
},
{
$replaceRoot:{newRoot: {$mergeObjects: [ { $arrayElemAt: ["$fromItems", 0 ] }, "$$ROOT" ] } }
},
{ $project :
{
id : "$follow id",
name: 1,
age: 1
}
}
])
So the point here is that you have a relation between id and follow id and after $lookup phase follow id becomes the new id since it's parent-child relation.
EDIT:
3.4 solution below
Follow.aggregate([
{
$match: { "id": "2" }
},
{
$lookup:{
from:"users",
localField:"follow id",
foreignField:"id",
as:"fromItems"
}
},
{
$project: {
id: "$follow id",
from: { $arrayElemAt: ["$fromItems", 0 ] }
}
},
{ $project :
{
id : 1,
name: "$from.name",
age: "$from.age"
}
}
])

How to extract value of nested object array?

I'm trying to extract all links IDs of the object array shown below. This is how I was trying to get that:
const linkIDs = array
.filter(d => d.links)
.map(d => d.links)
But this gives me a nested array, which is not what I wanted.
[
{
"id: "1",
"links": [
{
"id" : "Dn59y87PGhkJXpaiZ",
"type" : "article"
},
{
"id" : "PGhkJXDn59y87paiZ",
"type" : "article"
}
]
},
{
"id: "2",
"links": [
{
"id" : "GhkJXpaiZDn59y87P",
"type" : "article"
}
]
},
{
"id": "3"
}
]
So in this example I need the result
[ "Dn59y87PGhkJXpaiZ", "PGhkJXDn59y87paiZ", "GhkJXpaiZDn59y87P" ]
You can do like bellow, without using any other library.
var data = [
{
"id": "1",
"links": [
{
"id" : "Dn59y87PGhkJXpaiZ",
"type" : "article"
},
{
"id" : "PGhkJXDn59y87paiZ",
"type" : "article"
}
]
},
{
"id": "2",
"links": [
{
"id" : "GhkJXpaiZDn59y87P",
"type" : "article"
}
]
},
{
"id": "3"
}
];
var result = data.filter(e => e.links)
.map(e => e.links.map(link => link.id))
.reduce((a, b) => a.concat(b), []);
console.log(result);
I propose a more readable syntax in plain JS:
var data = [
{
"id": "1",
"links": [
{
"id" : "Dn59y87PGhkJXpaiZ",
"type" : "article"
},
{
"id" : "PGhkJXDn59y87paiZ",
"type" : "article"
}
]
},
{
"id": "2",
"links": [
{
"id" : "GhkJXpaiZDn59y87P",
"type" : "article"
}
]
},
{
"id": "3"
}
];
var result = data.filter(e => e.links)
.map(e => e.links)
.flat()
.map(e => e.id)
console.log(result);
You need to produce your array before mapping. Reduce in Js is very useful function ;)
arr = [
{
"id": "1",
"links": [
{
"id" : "Dn59y87PGhkJXpaiZ",
"type" : "article"
},
{
"id" : "PGhkJXDn59y87paiZ",
"type" : "article"
}
]
},
{
"id": "2",
"links": [
{
"id" : "GhkJXpaiZDn59y87P",
"type" : "article"
}
]
},
{
"id": "3"
}
];
var result = arr.filter(a=>a.links).reduce((acc, a) => {
return acc.concat(a.links)
}, []).map(a=>a.id);
console.log(result);
You can use lodash's flatMap() , where each filtered item is transformed using map().
DEMO
var data = [
{
"id": 1,
"links": [
{
"id": "Dn59y87PGhkJXpaiZ",
"type": "article"
},
{
"id": "PGhkJXDn59y87paiZ",
"type": "article"
}
]
},
{
"id": "2",
"links": [
{
"id": "GhkJXpaiZDn59y87P",
"type": "article"
}
]
},
{
"id": "3"
}
];
var result = _.flatMap(data, item =>
_(item.links)
.map(v => (v.id))
.value()
);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.12.0/lodash.js"></script>

Javascript menu recursive function bugs

//current jsfiddle
http://jsfiddle.net/0ht35rpb/45/
I am trying to loop through a json navigation tree - so that when a person goes to a particular page, it finds its alternative language counter-part.
//JSON
{
"langs" : [
{
"lang" : "de",
"lines" : {
"menu" : [
{
"title" : "Anleitung",
"link" : "/de/anleitung"
},
{
"title" : "Funktionen",
"link" : "/de/funktionen"
},
{
"title" : "Dienstleistungen",
"link" : "/de/dienstleistungen",
"children" : [
{
"title" : "Geistiges Eigentum",
"link" : "/de/dienstleistungen/geistiges-eigentum"
},
{
"title" : "Compliance",
"link" : "/de/dienstleistungen/compliance"
},
{
"title" : "Investment- und Beteiligungsrecht",
"link" : "/de/dienstleistungen/beteiligungsrecht"
},
{
"title" : "Mergers & Acquisitions",
"link" : "/de/dienstleistungen/mergers-and-acquisitions"
},
{
"title" : "Immobilienrecht",
"link" : "/de/dienstleistungen/immobilienrecht"
},
{
"title" : "Internet- und Datenschutzrecht",
"link" : "/de/dienstleistungen/internetrecht"
},
{
"title" : "Gesellschaftsrecht",
"link" : "/de/dienstleistungen/gesellschaftsrecht"
},
{
"title" : "Handelsrecht",
"link" : "/de/dienstleistungen/handelsrecht"
},
{
"title" : "Arbeitsrecht",
"link" : "/de/dienstleistungen/arbeitsrecht"
},
{
"title" : "Bankrecht",
"link" : "/de/dienstleistungen/bankrecht"
},
{
"title" : "Vertragsrecht",
"link" : "/de/dienstleistungen/vertragsrecht"
},
{
"title" : "Wettbewerbsrecht",
"link" : "/de/dienstleistungen/wettbewerbsrecht"
}
]
},
{
"title" : "Beliebte Projekte",
"link" : "/de/beliebte-projekte",
"children" : [
{
"title" : "Compliance",
"link" : "/de/beliebte-projekte/compliance",
"children" : [
{
"title" : "Haftungsrisiken für Geschäftsführern",
"link" : "/de/beliebte-projekte/compliance/haftungsrisken-geschaeftsfuehrern"
},
{
"title" : "Compliance-Prüfung KMU",
"link" : "/de/beliebte-projekte/compliance/compliance-pruefung-kmu"
}
]
}
]
}
],
"sign_in" : "Login"
}
},
{
"lang" : "en",
"lines" : {
"menu" : [
{
"title" : "How it works",
"link" : "/en/how-it-works"
},
{
"title" : "Features",
"link" : "/en/features"
},
{
"title" : "Services",
"link" : "/en/services",
"children" : [
{
"title" : "Intellectual property",
"link" : "/en/services/intellectual-property"
},
{
"title" : "Compliance",
"link" : "/en/services/compliance"
},
{
"title" : "Investment law",
"link" : "/en/services/investment-law"
},
{
"title" : "Mergers & Acquisitions",
"link" : "/en/services/mergers-and-acquisitions"
},
{
"title" : "Real estate law",
"link" : "/en/services/real-estate-law"
},
{
"title" : "Internet law and data privacy",
"link" : "/en/services/internet-law"
},
{
"title" : "Company law",
"link" : "/en/services/company-law"
},
{
"title" : "Trade law",
"link" : "/en/services/trade-law"
},
{
"title" : "Labour law",
"link" : "/en/services/labour-law"
},
{
"title" : "Bank law",
"link" : "/en/services/bank-law"
},
{
"title" : "Contract law",
"link" : "/en/services/contract-law"
},
{
"title" : "Competition law",
"link" : "/en/services/competition-law"
}
]
},
{
"title" : "Popular Projects",
"link" : "/en/popular-projects",
"children" : [
{
"title" : "Compliance",
"link" : "/en/popular-projects/compliance",
"children" : [
{
"title" : "Haf eng",
"link" : "/en/popular-projects/compliance/haf-eng"
},
{
"title" : "Compliance eng",
"link" : "/en/popular-projects/compliance/compliance-eng"
}
]
}
]
}
],
"sign_in" : "Sign in"
}
}
]
}
my js functions
so in this case
imagine
CURRENTLNG as en
CURRENTURL as /en/services
in fetchFooterUrls () - I want to return an array with ["/en/services", "/de/dienstleistungen"]
this code falls down in trying to get the 3rd level navigation counter parts
["/en/popular-projects/compliance/compliance-eng", "/de/beliebte-projekte/compliance/compliance-pruefung-kmu"]
getUrl (pairUrl, currentLng, enMenu, deMenu, obj) {
for (let k in obj) {
if (!obj.hasOwnProperty(k)) continue
if (obj[k].link === pairUrl) {
if (currentLng === 'de') {
return enMenu[k].link // get en link equivlant
} else {
return deMenu[k].link // get de link equivlant
}
} else {
if (obj[k].hasOwnProperty('children') && obj[k].children.length > 0) continue
this.getUrl(pairUrl, currentLng, enMenu[k].children, deMenu[k].children, obj[k].children)
}
}
}
//
getLanguagePair (currentLng, pairUrl) {
// 'find url in json tree'
var enMenu = linkTreeObject.langs[1].lines.menu
var deMenu = linkTreeObject.langs[0].lines.menu
let obj = {}
// find position in tree
if (currentLng === 'de') {
obj = deMenu
} else {
obj = enMenu
}
return this.getUrl(pairUrl, currentLng, enMenu, deMenu, obj)
}
fetchFooterUrls () {
let deUrl = ''
let enUrl = ''
if (CURRENTLNG === 'de') {
deUrl = CURRENTURL
enUrl = this.getLanguagePair(CURRENTLNG, this.props.location.pathname)
} else {
enUrl = CURRENTURL
deUrl = this.getLanguagePair(CURRENTLNG, this.props.location.pathname)
}
return [enUrl, deUrl]
}
//tried to make this snippet - any moderators here to resolve?
var linkTreeObject ={
"langs" : [
{
"lang" : "de",
"lines" : {
"menu" : [
{
"title" : "Anleitung",
"link" : "/de/anleitung"
},
{
"title" : "Funktionen",
"link" : "/de/funktionen"
},
{
"title" : "Dienstleistungen",
"link" : "/de/dienstleistungen",
"children" : [
{
"title" : "Geistiges Eigentum",
"link" : "/de/dienstleistungen/geistiges-eigentum"
},
{
"title" : "Compliance",
"link" : "/de/dienstleistungen/compliance"
},
{
"title" : "Investment- und Beteiligungsrecht",
"link" : "/de/dienstleistungen/beteiligungsrecht"
},
{
"title" : "Mergers & Acquisitions",
"link" : "/de/dienstleistungen/mergers-and-acquisitions"
},
{
"title" : "Immobilienrecht",
"link" : "/de/dienstleistungen/immobilienrecht"
},
{
"title" : "Internet- und Datenschutzrecht",
"link" : "/de/dienstleistungen/internetrecht"
},
{
"title" : "Gesellschaftsrecht",
"link" : "/de/dienstleistungen/gesellschaftsrecht"
},
{
"title" : "Handelsrecht",
"link" : "/de/dienstleistungen/handelsrecht"
},
{
"title" : "Arbeitsrecht",
"link" : "/de/dienstleistungen/arbeitsrecht"
},
{
"title" : "Bankrecht",
"link" : "/de/dienstleistungen/bankrecht"
},
{
"title" : "Vertragsrecht",
"link" : "/de/dienstleistungen/vertragsrecht"
},
{
"title" : "Wettbewerbsrecht",
"link" : "/de/dienstleistungen/wettbewerbsrecht"
}
]
},
{
"title" : "Beliebte Projekte",
"link" : "/de/beliebte-projekte",
"children" : [
{
"title" : "Compliance",
"link" : "/de/beliebte-projekte/compliance",
"children" : [
{
"title" : "Haftungsrisiken für Geschäftsführern",
"link" : "/de/beliebte-projekte/compliance/haftungsrisken-geschaeftsfuehrern"
},
{
"title" : "Compliance-Prüfung KMU",
"link" : "/de/beliebte-projekte/compliance/compliance-pruefung-kmu"
}
]
}
]
}
],
"sign_in" : "Login"
}
},
{
"lang" : "en",
"lines" : {
"menu" : [
{
"title" : "How it works",
"link" : "/en/how-it-works"
},
{
"title" : "Features",
"link" : "/en/features"
},
{
"title" : "Services",
"link" : "/en/services",
"children" : [
{
"title" : "Intellectual property",
"link" : "/en/services/intellectual-property"
},
{
"title" : "Compliance",
"link" : "/en/services/compliance"
},
{
"title" : "Investment law",
"link" : "/en/services/investment-law"
},
{
"title" : "Mergers & Acquisitions",
"link" : "/en/services/mergers-and-acquisitions"
},
{
"title" : "Real estate law",
"link" : "/en/services/real-estate-law"
},
{
"title" : "Internet law and data privacy",
"link" : "/en/services/internet-law"
},
{
"title" : "Company law",
"link" : "/en/services/company-law"
},
{
"title" : "Trade law",
"link" : "/en/services/trade-law"
},
{
"title" : "Labour law",
"link" : "/en/services/labour-law"
},
{
"title" : "Bank law",
"link" : "/en/services/bank-law"
},
{
"title" : "Contract law",
"link" : "/en/services/contract-law"
},
{
"title" : "Competition law",
"link" : "/en/services/competition-law"
}
]
},
{
"title" : "Popular Projects",
"link" : "/en/popular-projects",
"children" : [
{
"title" : "Compliance",
"link" : "/en/popular-projects/compliance",
"children" : [
{
"title" : "Haf eng",
"link" : "/en/popular-projects/compliance/haf-eng"
},
{
"title" : "Compliance eng",
"link" : "/en/popular-projects/compliance/compliance-eng"
}
]
}
]
}
],
"sign_in" : "Sign in"
}
}
]
};
getUrl (pairUrl, currentLng, enMenu, deMenu, obj) {
for (let k in obj) {
if (!obj.hasOwnProperty(k)) continue
if (obj[k].link === pairUrl) {
if (currentLng === 'de') {
return enMenu[k].link // get en link equivlant
} else {
return deMenu[k].link // get de link equivlant
}
} else {
if (obj[k].hasOwnProperty('children') && obj[k].children.length > 0) continue
this.getUrl(pairUrl, currentLng, enMenu[k].children, deMenu[k].children, obj[k].children)
}
}
}
//
getLanguagePair (currentLng, pairUrl) {
// 'find url in json tree'
var enMenu = linkTreeObject.langs[1].lines.menu
var deMenu = linkTreeObject.langs[0].lines.menu
let obj = {}
// find position in tree
if (currentLng === 'de') {
obj = deMenu
} else {
obj = enMenu
}
return this.getUrl(pairUrl, currentLng, enMenu, deMenu, obj)
}
console.log(getLanguagePair("en", "/en/how-it-works"))
Updated the jsfiddle. You had errors related to the recursive function call in the else part.
http://jsfiddle.net/gaganshera/0ht35rpb/51/
Changed it to
if (!obj[k].hasOwnProperty('children') || obj[k].children.length <= 0) continue;
var ret = getUrl(pairUrl, currentLng, enMenu[k].children, deMenu[k].children, obj[k].children);
if(typeof ret != 'undefined') return ret;
var linkTreeObject = {
"langs": [{
"lang": "de",
"lines": {
"menu": [{
"title": "Anleitung",
"link": "/de/anleitung"
}, {
"title": "Funktionen",
"link": "/de/funktionen"
}, {
"title": "Dienstleistungen",
"link": "/de/dienstleistungen",
"children": [{
"title": "Geistiges Eigentum",
"link": "/de/dienstleistungen/geistiges-eigentum"
}, {
"title": "Compliance",
"link": "/de/dienstleistungen/compliance"
}, {
"title": "Investment- und Beteiligungsrecht",
"link": "/de/dienstleistungen/beteiligungsrecht"
}, {
"title": "Mergers & Acquisitions",
"link": "/de/dienstleistungen/mergers-and-acquisitions"
}, {
"title": "Immobilienrecht",
"link": "/de/dienstleistungen/immobilienrecht"
}, {
"title": "Internet- und Datenschutzrecht",
"link": "/de/dienstleistungen/internetrecht"
}, {
"title": "Gesellschaftsrecht",
"link": "/de/dienstleistungen/gesellschaftsrecht"
}, {
"title": "Handelsrecht",
"link": "/de/dienstleistungen/handelsrecht"
}, {
"title": "Arbeitsrecht",
"link": "/de/dienstleistungen/arbeitsrecht"
}, {
"title": "Bankrecht",
"link": "/de/dienstleistungen/bankrecht"
}, {
"title": "Vertragsrecht",
"link": "/de/dienstleistungen/vertragsrecht"
}, {
"title": "Wettbewerbsrecht",
"link": "/de/dienstleistungen/wettbewerbsrecht"
}]
}, {
"title": "Beliebte Projekte",
"link": "/de/beliebte-projekte",
"children": [{
"title": "Compliance",
"link": "/de/beliebte-projekte/compliance",
"children": [{
"title": "Haftungsrisiken für Geschäftsführern",
"link": "/de/beliebte-projekte/compliance/haftungsrisken-geschaeftsfuehrern"
}, {
"title": "Compliance-Prüfung KMU",
"link": "/de/beliebte-projekte/compliance/compliance-pruefung-kmu"
}]
}]
}],
"sign_in": "Login"
}
}, {
"lang": "en",
"lines": {
"menu": [{
"title": "How it works",
"link": "/en/how-it-works"
}, {
"title": "Features",
"link": "/en/features"
}, {
"title": "Services",
"link": "/en/services",
"children": [{
"title": "Intellectual property",
"link": "/en/services/intellectual-property"
}, {
"title": "Compliance",
"link": "/en/services/compliance"
}, {
"title": "Investment law",
"link": "/en/services/investment-law"
}, {
"title": "Mergers & Acquisitions",
"link": "/en/services/mergers-and-acquisitions"
}, {
"title": "Real estate law",
"link": "/en/services/real-estate-law"
}, {
"title": "Internet law and data privacy",
"link": "/en/services/internet-law"
}, {
"title": "Company law",
"link": "/en/services/company-law"
}, {
"title": "Trade law",
"link": "/en/services/trade-law"
}, {
"title": "Labour law",
"link": "/en/services/labour-law"
}, {
"title": "Bank law",
"link": "/en/services/bank-law"
}, {
"title": "Contract law",
"link": "/en/services/contract-law"
}, {
"title": "Competition law",
"link": "/en/services/competition-law"
}]
}, {
"title": "Popular Projects",
"link": "/en/popular-projects",
"children": [{
"title": "Compliance",
"link": "/en/popular-projects/compliance",
"children": [{
"title": "Haf eng",
"link": "/en/popular-projects/compliance/haf-eng"
}, {
"title": "Compliance eng",
"link": "/en/popular-projects/compliance/compliance-eng"
}]
}]
}],
"sign_in": "Sign in"
}
}]
};
function getUrl(pairUrl, currentLng, enMenu, deMenu, obj) {
for (let k in obj) {
if (!obj.hasOwnProperty(k)) continue
if (obj[k].link === pairUrl) {
if (currentLng === 'de') {
return enMenu[k].link // get en link equivlant
} else {
return deMenu[k].link // get de link equivlant
}
} else {
if (!obj[k].hasOwnProperty('children') || obj[k].children.length <= 0) continue;
var ret = getUrl(pairUrl, currentLng, enMenu[k].children, deMenu[k].children, obj[k].children);
if(typeof ret != 'undefined') return ret;
}
}
}
function getLanguagePair(currentLng, pairUrl) {
// 'find url in json tree'
var enMenu = linkTreeObject.langs[1].lines.menu
var deMenu = linkTreeObject.langs[0].lines.menu
let obj = {}
// find position in tree
if (currentLng === 'de') {
obj = deMenu
} else {
obj = enMenu
}
return getUrl(pairUrl, currentLng, enMenu, deMenu, obj)
}
//works
console.log(getLanguagePair("en", "/en/how-it-works"))
console.log(getLanguagePair("en", "/en/popular-projects"))
console.log(getLanguagePair("de", "/de/anleitung"))
console.log(getLanguagePair("de", "/de/beliebte-projekte"))
//fail
console.log(getLanguagePair("en", "/en/services/compliance"))
console.log(getLanguagePair("en", "/en/popular-projects/compliance"))
console.log(getLanguagePair("en", "/en/popular-projects/compliance/compliance-eng"))
there is a problem in your recursive function. If you don't match the url at the first function call, you recursively call the function again but you don't return it.
function get_10_recursive(number){
if(number>=10) return 10;
else return get_10_recursive(number++);
}
In this example, if the number is smaller than 10, the function is recursively called until it encounter a return statement, after this, it retrace the stack and returns you the correct result. If you remove the return statement in the third line the code is executed as well but it returns the result only of the first call, which is undefined.
The problem in your code is that, if you place a return inside the for loop, the loop gets interrupted and you won't check the next strings, so you have to store the results of the function call in a temporary variable and return it only if it's truthy (aka it's not undefined).
Your getUrl function becomes like this:
function getUrl(pairUrl, currentLng, enMenu, deMenu, obj) {
for (var k in obj) {
if (obj[k].link === pairUrl) {
if (currentLng === 'de') {
return enMenu[k].link; // get en link equivlant
} else {
return deMenu[k].link; // get de link equivlant
}
} else {
if (obj[k].hasOwnProperty('children')){
var tmp = getUrl(pairUrl, currentLng, enMenu[k].children, deMenu[k].children, obj[k].children);
if(tmp) return tmp; // check if it found the match successfully
}
}
}
}
PS: I remvoed the if (!obj.hasOwnProperty(k)) continue because it was useless

Categories

Resources