JSON Path: Outputting value plus parent hierarchically - javascript

I'm new to JSON Path, so this may be simpler than I expect, if it's even possible.
I have a JSON block that consists of a set of groups, with each group having a set of fields. Each group also has a sequence, as does each field. The field sequence represents order within a group, and the group sequence represents the display order of the group itself.
I generated this programmatically in C# off of a flat list of items (groups and fields) with different sequence values, so I want to validate my output and, by extension, my grouping algorithm.
The JSON block looks (vastly simplified) like this:
{
"groups": [
{
"sequence": 0,
"fields": [
{
"sequence": 0
},
{
"sequence": 1
},
{
"sequence": 2
}
]
},
{
"sequence": 1,
"fields": [
{
"sequence": 0
},
{
"sequence": 1
}
]
},
{
"sequence": 2,
"fields": [
{
"sequence": 0
},
{
"sequence": 1
},
{
"sequence": 2
}
]
}
]
}
I'm trying to validate this with JSON Path. For this, I don't have a tool, so I'm using the jsonpath online evaluator.
What I'm aiming for is output along the lines of this:
'0'
'sequence' => '0'
'fields'...
'0'
'sequence' => '0'
'1'
'sequence' => '1'
'2'
'sequence' => '2'
// etc...
In other words, I'm looking for a JSON path query that can return the sequence of each group plus the sequence of each field in the group, in a hierarchy.
To get the sequence of the groups, I'm using the following. This works fine, and gives me useful output, since groups are the top-level item already:
$.groups[*].sequence
Output:
'0' => "0"
'1' => "1"
'2' => "2"
To get the sequence of the fields in the groups, I'm using the following. The output here is less useful, as it's a flat list that can get difficult to read if I have dozens or more fields spread out across several groups.
$.groups[*].fields[*].sequence
Output:
'0' => "0"
'1' => "1"
'2' => "2"
'3' => "0"
'4' => "1"
'5' => "0"
'6' => "1"
'7' => "2"
So ultimately, the question is this: is there a JSON path query that will let me get the information I need here hierarchically? Or am I using the wrong tool for the job? I suppose I could write a few lines of code in JavaScript that will let me do this if I have to, but it seems like JSON path might be a powerful tool to learn, so if I can do it here I've learned something.

You do not need a variable sequence. When you need sequence, move item from one group to another, sort you can use array in object, and object in array.
Array use to sort, move items, change sequence. Objects to grouping of attributes within a single item
var groups =
[
{"fields": [
{name: 'field1'},
{name: 'field2'},
{name: 'field3'}
],
},
{"fields": [
{name: 'field1'},
{name: 'field2'},
{name: 'field3'}
]
},
{"fields": [
{name: 'field1'},
{name: 'field2'},
{name: 'field3'}
]
}
];
console.log(groups[0].fields); // Array [ Object, Object, Object ]
console.log(groups[2].fields[0].name); // field1
Function splice is the best to change sequence. In same fields, and another fields
Example for change sequence in same fields
var oldIndex = 2, newIndex = 0, item = groups[0].fields.splice(oldIndex, 1)[0];
console.log(item);
groups[0].fields.splice(newIndex, 0, item);
console.log(groups);

Related

Filter nested array in object based on specific values of another array [duplicate]

This question already has answers here:
Filter array of objects based on another array in javascript
(10 answers)
Closed 7 months ago.
I have an array of Objects, and every object has an array of strings (tags), I need to filter the array of objects based on another array.
data: [
{
"id":"Nerium",
"tags":["CMS Selection", "Experience Design", "Development","UX"],
"featured":0
},
{
"id":"WesternDigital",
"tags":["Digital Strategy", "Analytics", "Example"],
"featured":1
},
{
"id":"Example",
"tags":["Example", "Analytics", "UX"],
"featured": 0,
},
I need to filter the above data based on an Array like this:
activeTags: ['UX', 'Example']
And the objects of Data I filter need to specifically have the values inside activeTags, in this case if for example an Object has 'UX' but it doesn't have 'Example', I don't return it.
Expected output:
data: [{
"id": "Example",
"tags": ["Example", "Analytics", "UX"],
"featured": 0,
}]
Or it should return every Object that has tags that specifically have the values in activeTags
This should work
const data = [
{
id: "Nerium",
tags: ["CMS Selection", "Experience Design", "Development", "UX"],
featured: 0,
},
{
id: "WesternDigital",
tags: ["Digital Strategy", "Analytics", "Example"],
featured: 1,
},
{
id: "Example",
tags: ["Example", "Analytics", "UX"],
featured: 0,
},
];
const activeTags = ["UX", "Example"];
const filtered = data.filter(({ tags }) =>
activeTags.every((tag) => tags.includes(tag))
);
console.log(filtered);
you can use .every to check that the object has all the active tags
I haven't tested, but I think the following should work:
const result = data.filter( record =>
activeTags.every( tag =>
record.tags.includes( tag )
)
);
filter() returns array with only elements that pass its function test. every() returns true only if every element passes its function test. includes() will test if the element is included in the record.tags array.

map two 1D arrays into a 2D array and then fill with known values

I', just wondering about the best way to approach this problem. I have two single dimension arrays which I need to merge into a grid, effectively the first array becomes rows and the second array becomes columns - both are of unknown size.
I am thinking nested loops and .push but is there a more elegant solution.
The second part of the problem is slightly trickier. Each of the grid cells will have a key assigned based on the row and column data. I have a third array which contains this key, as a property of the object in the array index and I need to inject (or link) this object to the correct cell in the 2D array. Typically around 80% of the grid will have an associated object in the third array.
The data sets are not huge; the largest grid will only be about 400 cells so an iterative solution will work but it feels dirty. Is there a better 'computer science' method or a javascript array method that will let me achieve what I want.
If not, is there any significant tradeoff between iterating in the items array and trying to find the correct cell in the 2D array or iterating the 2D array to and try to find the matching object in the items array, bearing in mind that I am matching against the item property and not a key.
Sample code below
let arrRow = [
{"code":"S", "desc":"small"},
{"code":"M", "desc":"med"},
{"code":"L", "desc":"large"}
];
let arrCol = [
{"code":"R", "desc":"Red"},
{"code":"G", "desc":"Green"},
{"code":"B", "desc":"Blue"}
];
let arrItems= [
{"item":"SR", "desc":"Small Red"},
{"item":"SB", "desc":"Small Blue"},
{"item":"MB", "desc":"Med Blue"},
{"item":"LB", "desc":"Large Blue"},
{"item":"SG", "desc":"Small Green"},
{"item":"LG", "desc":"Large Green"}
];
As per respondent's request. The desired outcome would be
[
[
{"key":"SR", "value":{"item":"SR", "desc":"Small Red"}},
{"key":"SG", "value":{"item":"SG", "desc":"Small Green"}},
{"key":"SB", "value":{"item":"SB", "desc":"Small Blue"}
],
{"key":"MR", "value":{}},
{"key":"MG", "value":{}},
{"key":"MB", "value":{"item":"MB", "desc":"Med Blue"}}
],
{"key":"LR", "value":{}},
{"key":"LG", "value":{"item":"LG", "desc":"Large Green"}},
{"key":"LB", "value":{"item":"LB", "desc":"Large Blue"}}
]
]
Alternatively the value could just be the index of the element in the item array which is probably more memory efficient
You could take a Map for data and iterate rows and columns.
var arrRow = [{ code: "S", desc: "small" }, { code: "M", desc: "med" }, { code: "L", desc: "large" }],
arrCol = [{ code: "R", desc: "Red" }, { code: "G", desc: "Green" }, { code: "B", desc: "Blue" }],
arrItems = [{ item: "SR", desc: "Small Red" }, { item: "SB", desc: "Small Blue" }, { item: "MB", desc: "Med Blue" }, { item: "LB", desc: "Large Blue" }, { item: "SG", desc: "Small Green" }, { item: "LG", desc: "Large Green" }],
map = arrItems.reduce((m, o) => m.set(o.item, o), new Map),
result = arrRow.map(r => arrCol.map(c => (map.get(r.code + c.code) || {}).desc || ''));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

using R.groupWith (ramda)

I'm trying to group the following array acc to dateValue, but can't seem to get it to work. What am I missing here?
const dates = [
{"id":83,"dateValue":"2017-05-24"},
{"id":89,"dateValue":"2017-05-28"},
{"id":91,"dateValue":"2017-05-25"},
{"id":78,"dateValue":"2017-05-24"},
{"id":84,"dateValue":"2017-05-25"}
]
const groups = R.groupWith(R.eqProps('dateValue'),dates)
console.log(groups)
<script src="//cdn.jsdelivr.net/ramda/latest/ramda.min.js"></script>
I've included a link to ramda repl with this code loaded
expected result:
[ [ { dateValue: "2017-05-24", id: 83 },
{ dateValue: "2017-05-24", id: 78 } ],
[ { dateValue: "2017-05-28", id: 89 } ],
[ { dateValue: "2017-05-25", id: 91 } ],
[ { dateValue: "2017-05-25", id: 84 } ] ]
There are several differences between groupBy and groupWith.
groupBy accepts a function which yields a grouping key for a single item. groupWith accepts a binary predicate that says whether two items match.
groupBy collects all items into single collections. groupWith only collects matching itemss which are consecutive.
groupBy returns an object that maps those keys to the list of matching items. groupWith returns a list of lists of (again consecutive) matching items.
It's that second point which is tripping you up. You probably want groupBy:
R.groupBy(R.prop('dateValue'))(dates)
// or
R.compose(R.values, R.groupBy(R.prop('dateValue')))(dates);
You can see this in action on the Ramda REPL.

Why is it not possible to find documents with '$all' modifier?

I have the following documents:
{
_id: 1
title: "oneItem"
},
{
_id: 2,
title: "twoItem"
}
When I try to find these documents by using the following command:
db.collection.documents.find({_id: {$in: [1, 2]}});
I get these two documents but when I try to find these documents by using the following query:
db.collection.documents.find({_id: {$all: [1, 2]}});
I get nothing. Can you explain what's the problem? Basically I need to find all documents with _id 1 and 2 and if none exist then fail.
The reasoning is actually quite simple in that $in and $all have two completely different functions. The documentation links are there, but to explain:
Consider these documents:
{
_id: 1,
items: [ "a", "b" ]
},
{
_id: 2,
items: [ "a", "b", "c" ]
}
$in - provides a list of arguments that can possibly match the value in the field being tested. This would match as follows:
db.collection.find({ items: {$in: [ "a", "b", "c" ] }})
{
_id: 1,
items: [ "a", "b" ]
},
{
_id: 2,
items: [ "a", "b", "c" ]
}
$all - provides a list where the field being matched is expected to be an array and all of the listed elements are present in that array. E.g
db.collection.find({ items: {$all: [ "a", "b", "c" ] }})
{
_id: 2,
items: [ "a", "b", "c" ]
}
Hence why your query does not return a result, the field is not an array and does not contain both elements.
The MongoDB operator reference is something you should really read through.
As your your statement, ["I need to find all documents with _id 1 and 2 and if someone from them does not exists then fail."], matching various criteria is easy as you see in the usage of $in. Your problem is you want a whole set to match or otherwise return nothing ("fail"). This I have already explained to you an some length in a previous question, but to re-iterate:
db.collection.aggregate([
// Match on what you want to find
{$match: { list: {$in: [1,2]} }},
// Add the found results to a distinct *set*
{$group: { _id: null, list: {$addToSet: "$_id"} }},
// Only return when *all* the expected items are in the *set*
{$match: { list: {$all: [1,2]} }}
])
So after that manipulation, this will only return a result if all of the items where found. That is how we use $all to match in this way.

How to pass list in JavaScript?

I am trying to dynamically send a list object (as below) in JavaScript.
I am trying to setup a dynamic grid which accepts dynamic column names (instead of hardcoding the columns)
I am trying to create columnmap dynamically that will be used by grid, something like below,
columMap : {
'Header' : [
{ title : "Title", field : "Title" },
{ title : "Created", field : "Created" },
{ title : "Created By", field : "CreatedBy.Account" }
]
I tried with var list={field : 'Name',title:'Name'}.. This works fine for one column but does't work for multiple columns. I tried array too, didn't work.. Anyone has any suggestions?
[] represents an empty array
[1, 2, 3] is an array of three numbers
[ { a: 1 }, { a: 1 } ] is an array of objects
[ 1, "a", { a: 3 } ] an array does not care what type it holds
So...
var list =
[
{field : 'Name',title:'Name'}
];
Sorry, it was my mistake... I forgot to remove [] when I was passing my list object hence it was not able to set the value..
I got it resolved by passing list as below..
var list = [{ field: 'Name',title: 'Name' },{ field:'ContextNamePathRaw',title: 'Ownership Hierarchy'} ];
Thanks for your help!!!
BB

Categories

Resources