I have a json object as follows,
{
"category": "music",
"location": {
"city": "Braga"
},
"date": {
"start": {
"$gte": "2017-05-01T18:30:00.000Z"
},
"end": {
"$lt": "2017-05-12T18:30:00.000Z"
}
}
}
i need to create a query string as follows,
category=music | location.city = Braga | date.start.$gte = 2017-05-01T18:30:00.000Z | date.end.$lt = 2017-05-12T18:30:00.000Z
How can I achieve this?
This is what i have tried.
_.each(this.filter, (val: string, key: string) => {
if (key && val) {
filterArray.push(`${key}=${val}`);
}
});
You could iterate the keys and build a path to the value. Later join pathes and add value and join to the final string.
function getParts(object) {
function iter(o, p) {
Object.keys(o).forEach(function (k) {
if (o[k] && typeof o[k] === 'object') {
iter(o[k], p.concat(k));
return;
}
result.push(p.concat(k).join('.') + ' = ' + o[k]);
});
}
var result = [];
iter(object, []);
return result.join(' | ');
}
var object = { "category": "music", "location": { "city": "Braga" }, "date": { "start": { "$gte": "2017-05-01T18:30:00.000Z" }, "end": { "$lt": "2017-05-12T18:30:00.000Z" } } },
string = getParts(object);
console.log(string);
Sorry, I'm late, but still.
Method walk recursively runs through your JSON and calls callback function with chain of keys and value as arguments.
Then convert uses walk to translate JSON into your format:
var walk = function( data, iterator, stack ) {
var key;
stack = stack || [];
for ( key in data ) {
if ( typeof data[ key ] === 'string' ) {
iterator( stack.concat( [ key ] ), data[ key ] );
} else {
walk( data[ key ], iterator, stack.concat( [ key ] ) );
}
}
};
var convert = function( data ) {
var result = [];
walk( data, function( keys, value ) {
result.push( keys.join( '.' ) + ' = ' + value );
} );
return result.join( ' | ' );
};
var query_string = convert( /* your JSON here */ );
Related
Given the following object:
const ourObject = {
"payload": {
"streams": [
{
"children": {
"2165d20a-6276-468f-a02f-1abd65cad618": {
"additionalInformation": {
"narrative": {
"apple": "A",
"banana": "B"
},
"myInventory": {
"fruits": [
{
"name": "apple"
},
{
"name": "banana"
}
]
}
}
}
}
}
]
}
};
We're trying to find the path of myInventory, the issue is that the children's uuid will be different each time. Any idea how we can get the path to myInventory by providing it as a key and get the json path to it?
If things are dynamic, a programmatic key search could help
const ourObject = {
"payload": {
"streams": [
{
"children": {
"2165d20a-6276-468f-a02f-1abd65cad618": {
"additionalInformation": {
"narrative": {
"apple": "A",
"banana": "B"
},
"myInventory": {
"fruits": [
{
"name": "apple"
},
{
"name": "banana"
}
]
}
}
}
}
}
]
}
};
const getPath = (key, o) => {
if (!o || typeof o !== "object") {
return "";
}
const keys = Object.keys(o);
for(let i = 0; i < keys.length; i++) {
if (keys[i] === key ) {
return key;
}
const path = getPath(key, o[keys[i]]);
if (path) {
return keys[i] + "." + path;
}
}
return "";
};
const getValueForKey = (key, o) => {
if (!o || typeof o !== "object") {
return undefined;
}
const keys = Object.keys(o);
for(let i = 0; i < keys.length; i++) {
if (keys[i] === key ) {
return o[key];
}
const value = getValueForKey(key, o[keys[i]]);
if (value) {
return value;
}
}
return undefined;
}
console.log(getPath("myInventory", ourObject))
console.log(getValueForKey("myInventory", ourObject))
Not sure if I understand the question right but
let uuid = '2165d20a-6276-468f-a02f-1abd65cad618';
ourObject.payload.streams[0].children[uuid].additionalInformation.myInventory
var changingKey = Object.keys(ourObject["payload"]["streams"][0]["children"])[0];
console.log(ourObject["payload"]["streams"][0]["children"][changingKey]["additionalInformation"]["myInventory"]);
Okay, you could create a helper function that gets the UUID. Since it's an object, the lookup is close to O(1) especially given the case that the children has only one key-value pair here.
function getUUIDFromPayload(payload) {
let obj = payload.streams[0].children
let uuid = Object.keys(obj)[0]
return uuid
}
Usage
const uuid = getUUIDFromPayload(payload)
ourObject.payload.streams[0].children[uuid].additionalInformation.myInventory
I am converting JSON keys to the list with dot-notation. If any dot is there represent nested jsonobject and if any [](array notation) is there resents jsonarray.
var keyify = (obj, prefix = '') =>
Object.keys(obj).reduce((res, el) => {
if (Array.isArray(obj[el])) {
return [...res, ...keyify(obj[el][0], prefix + el + '[].')];
} else if (typeof obj[el] === 'object' && obj[el] !== null) {
return [...res, ...keyify(obj[el], prefix + el + '.')];
} else {
return [...res, prefix + el];
}
}, []);
Above is the sample code that I am using for the converion. If input is
{
"input": {
"test": {
"phone": [
{
"phone1": "123"
}
]
}
},
"customer": [
{
"lastname": "def",
"firstname": "abc"
}
]
}
Output will be:
[ 'input.test.phone[].phone1',
'customer[].lastname',
'customer[].firstname' ]
But the above code searches for only first JSONObject's keys in the JSONArray. But if the input is like this:
{
"input": {
"test": {
"phone": [
{
"phone1": "123"
},
{
"a": "456"
}
]
}
},
"customer": [
{
"lastname": "def",
"firstname": "abc"
}
]
}
Then in the above JSON case the code will give output :
[ 'input.test.phone[].phone1',
'customer[].lastname',
'customer[].firstname' ]
So, the key a is missing only phone1 is coming in the list.So, how to get if multiple json keys are there then get keys with index of first occurence.
Expected output
[ 'input.test.phone[0].phone1',
'input.test.phone[1].a',
'customer[0].lastname',
'customer[0].firstname' ]
And if the JSONarray is value then it should be replaced by empty string.
For input:
const data = {
"input": {
"test": {
"phone": [
{
"phone1": ["123456"]
},
{
"a": ["1","2","3","4"]
}
]
}
},
"customer": [
{
"lastname": "def",
"firstname": "abc"
}
]
}
In this case "phone1": ["123456"] and "a": ["1","2","3","4"] are Json array as values this case lis will be like:
Expected Output:
[ 'input.test.phone[0].phone1',//instead of 'input.test.phone[0].phone1[0]'
'input.test.phone[1].a',//instead of 'input.test.phone[1].a[0]','input.test.phone[1].a[1]','input.test.phone[1].a[2]','input.test.phone[1].a[3]',
'customer[0].lastname',
'customer[0].firstname' ]
In the above case jsonarray should be considered as value not key.
You could use for...in loop to create recursive function for this and check if the current data input is an array or not to add dot or square brackets.
const data = { "input": { "test": { "phone": [ { "phone1": ["123456"] }, { "a": ["1","2","3","4"] } ] } }, "customer": [ { "lastname": "def", "firstname": "abc" } ] }
function parse(data, prev = '') {
const result = []
const check = data => {
if (typeof data !== 'object') {
return false
}
if (Array.isArray(data)) {
if (data.some(e => (typeof e != 'object'))) {
return false
}
}
return true;
}
for (let i in data) {
let dot = prev ? '.' : ''
let str = Array.isArray(data) ? `[${i}]` : dot + i
let key = prev + str;
if (check(data[i])) {
result.push(...parse(data[i], key))
} else {
result.push(key)
}
}
return result
}
const result = parse(data);
console.log(result)
You can traverse through the scope of the object and capture any paths that have a non-object value.
This is an extremely uncoupled and generic soulution.
const traverse = (obj, visitorFn, scope = []) => {
for (let key in obj) {
visitorFn.apply(this, [key, obj[key], scope]);
if (obj[key] !== null && typeof obj[key] === 'object') {
traverse(obj[key], visitorFn, scope.concat(key));
}
}
}
const scopeToPath = (obj) => obj.reduce((path, key) =>
path + (!isNaN(key) ? `[${key}]` : `.${key}`), '').substring(1);
const findObjectPaths = (obj) => {
let paths = [];
traverse(obj, (key, value, scope) => {
if (typeof value !== 'object') {
paths.push(scopeToPath(scope.concat(key)));
}
});
return paths;
};
console.log(findObjectPaths(getData()));
function getData() {
return {
"input": {
"test": {
"phone": [{ "phone1": "123" }, { "a": "456" }]
}
},
"customer": [{ "lastname": "def", "firstname": "abc" }]
};
}
.as-console-wrapper { top: 0; max-height: 100% !important; }
You could take a nested approach by having a look to the types of the object.
function flat(object, keys = '') {
if (!object || typeof object !== 'object') return [keys];
if (Array.isArray(object))
return object.every(o => !o|| typeof o!== 'object')
? [keys]
: object.flatMap((o, i, { length }) =>
flat(o, `${keys}[${length === 1 ? '' : i}]`));
return Object
.entries(object)
.flatMap(([k, v]) => flat(v, `${keys}${keys && '.'}${k}`));
}
var data = { input: { test: { phone: [{ phone1: ["123456"] }, { a: ["1", "2", "3", "4"] }] } }, customer: [{ lastname: "def", firstname: "abc" }] },
result = flat(data);
console.log(result);
here my issue i unable to get the dynamic key pair value from the dynamic json
below is my json
var d = {
"pexels-photo.jpeg": {
"information": "laptop",
"desc": {
"mimetype": "image/jpeg",
"id": "shsj44",
"file_id": "pexels-photo.jpeg"
},
"_id": "shsj44"
}
}
here i tried below
Object.keys(d).forEach(function(key){
var value = d[key];
console.log(key + ':' + value) ;
});
i want to get the id value "_id" & "file_id" values
You can use Destructuring assignment
var d = {"dynamic": {"information": "laptop","desc": { "mimetype": "image/jpeg","id": "shsj44","file_id": "pexels-photo.jpeg" },"_id": "shsj44"}}
let dynamicKey = Object.keys(d)[0]
let {[dynamicKey]:{desc:{
file_id
},_id}} = d
console.log(file_id, '\n', _id)
That is because of the + before the value, which will try to concatenate the value and you will see [object object]
var d = {
"pexels-photo.jpeg": {
"information": "laptop",
"desc": {
"mimetype": "image/jpeg",
"id": "shsj44",
"file_id": "pexels-photo.jpeg"
},
"_id": "shsj44"
}
}
Object.keys(d).forEach(function(key) {
let value = d[key];
console.log(key + ' : ', value);
console.log(key + ' : ', value.desc.id);
});
You need to check whether the value is object or not, if yes then you need to loop over it again.
Following code will print every key-value pair in d
export class AppComponent implements OnInit {
d = {
'pexels-photo.jpeg': {
'information': 'laptop',
'desc': {
'mimetype': 'image/jpeg',
'id': 'shsj44',
'file_id': 'pexels-photo.jpeg'
},
'_id': 'shsj44'
}
};
ngOnInit(): void {
this.calc(this.d);
}
calc(val) {
Object.keys(val).forEach(key => {
const value = val[key];
if (typeof (value) === 'object') {
this.calc(value);
} else {
console.log(key + ':' + value);
}
});
}
}
Try this :
var d = {
"pexels-photo.jpeg": {
"information": "laptop",
"desc": {
"mimetype": "image/jpeg",
"id": "shsj44",
"file_id": "pexels-photo.jpeg"
},
"_id": "shsj44"
}
};
Object.keys(d).filter(key => {
Object.keys(d[key]).filter(item => {
if (item === 'desc') {
Object.keys(d[key][item]).filter(elem => {
if ((elem === 'id') || (elem === 'file_id')) {
console.log(elem + ' : ' + d[key][item][elem]);
}
});
}
})
});
I want to merge multiple arrays into one big array with shared keys.
What I've tried:
var conditions = [];
if( aa != undefined )
{
conditions.push( { "query" : { "must" : { "aa" : "this is aa" } } } );
}
if( bb != undefined )
{
conditions.push( { "query" : { "must" : { "bb" : "this is bb" } } } );
}
The above code is giving:
[
{
"query": {
"must": {
"aa": "this is aa"
}
}
},
{
"query": {
"must": {
"bb": "this is bb"
}
}
}
]
But I need this:
[
{
"query": {
"must": [
{
"aa": "this is aa"
},
{
"bb": "this is bb"
}
]
}
}
]
I am able to do it with PHP but I need to do it in native javascript or using underscore.js
Define the object your pushing - push everything to the inner array first - then push the object to the outer array:
var conditions = [];
var query = { query: {} };
if( aa != undefined ) {
if (!query["query"]["must"]) {
query["query"]["must"] = [];
}
//conditions.push( { "query" : { "must" : { "aa" : "this is aa" } } } );
query["query"]["must"].push({ "aa" : "this is aa" });
}
if( bb != undefined ) {
if (!query["query"]["must"]) {
query["query"]["must"] = [];
}
//conditions.push( { "query" : { "must" : { "bb" : "this is bb" } } } );
query["query"]["must"].push({ "bb" : "this is bb" });
}
conditions.push(query);
For each descendant of conditions, check if it exists, create it if it doesn't.
Then, finally, push your new object:
function addCondition(conditions, key, value) {
conditions[0] = conditions[0] || {};
conditions[0].query = conditions[0].query || {};
conditions[0].query.must = conditions[0].query.must || [];
var o = {};
o[key] = value;
conditions[0].query.must.push( o );
}
var conditions = [];
var aa = 1, bb = 1;
if (typeof(aa) !== 'undefined')
addCondition(conditions, "aa", "this is aa" );
if (typeof(bb) !== 'undefined')
addCondition(conditions, "bb", "this is bb" );
if (typeof(cc) !== 'undefined')
addCondition(conditions, "cc", "this is cc" );
document.getElementById('results').innerHTML = JSON.stringify(conditions, null, 2);
<pre id="results"></pre>
It's not quite trivial, because I see you want to make an array out of the last inner property.
Do those Objects you push into the conditions array already exist or are you defining them yourself?
You can solve your problem with a recursive function like this I believe:
EDIT: The code produces the exact result you wanted now.
var object1 = {
query: {
must: {
aa: "this is aa"
}
}
}
var object2 = {
query: {
must: {
bb: "this is bb"
}
}
}
var conditions = {};
function mergeObjects(object, parentObject){
for(var prop in object){
if(parentObject.hasOwnProperty(prop)){
if(typeof parentObject[prop] === "object" && shareProperties(parentObject[prop], object[prop])){
mergeObjects(object[prop], parentObject[prop])
}else{
parentObject[prop] = [parentObject[prop], object[prop]];
}
}else{
parentObject[prop] = object[prop];
}
}
}
function shareProperties(obj1, obj2){
for(var prop in obj1){
if(obj2.hasOwnProperty(prop)){
return true;
}
}
return false;
}
mergeObjects(object1, conditions);
mergeObjects(object2, conditions);
Output:
"{"query":{"must":[{"aa":"this is aa"},{"bb":"this is bb"}]}}"
I am trying to loop all the values of an array and push that looped data into another array.
For example:
{
"cat": [
{
"view": [
{
"ent": [
{
"data": [
{}
],
"label": "abcd"
},
{
"data": [
{}
],
"label": "efgh"
}
]
}
]
}
]
I need to iterate until label and bring all the values of label into an array. This is what I have tried.
The issue is I am just getting the last value of label i.e. won in my array variable.
JS:
var ArrL = scope.res.cat;
var Array = [];
for(var i=0;i<ArrL.length;i++){
var ArrF = ArrL[i].view;
for(var j=0;j<ArrF.length;j++){
var ArrE = ArrF[j].ent;
for(var k=0;k<ArrE.length;k++){
var ArrLa = ArrE[k].label;
}
}
Array.push(ArrLa);
}
console.log(Array);
Expected output is ['joy','won'] but output after running the program is ['won'].
Since your Q is flagged as jquery, you can do this:
var cat = [
{
view: [
{
ent: [
{
data: [
{
key: "id",
value: "00"
},
{
key: "cid",
value: "123"
}
],
label: "joy"
},
{
key: "id",
value: "11"
},
{
key: "cid",
value: "234"
}
], // end ent
label: "won"
},
] //end view
}
];
var labels = [];
$.map( cat, function flattener( node ) {
if ( $.isPlainObject( node ) && node.hasOwnProperty('label') ) {
labels.push( node.label );
}
return ($.isArray( node ) || $.isPlainObject( node )) ? $.map( node, flattener) : node;
} );
console.log( labels );
Fiddle: http://jsfiddle.net/fFwQ6/
Thing to note is that order will be dictated by depth: deeper labels come last.
UPDATE:
It is easy to turn it into an utility function:
function grabKeys( source, keyName ) {
var values = [];
$.map( source, function flattener( node ) {
if ( $.isPlainObject( node ) && node.hasOwnProperty(keyName) ) {
values.push( node[keyName] );
}
return ($.isArray( node ) || $.isPlainObject( node )) ? $.map( node, flattener) : node;
} );
return values;
}
var labels = grabKeys( cat, 'label' );
var cids = grabKeys( cat, 'cid' );
UPDATE 2: Since 'cid' is a key value and not a name, we must use a slightly different method. Sorry I did not noticed it previously.
function grabPairedKeys( source, keyValue, keyName1, keyName2 ) {
keyName1 = keyName1 || 'key';
keyName2 = keyName2 || 'value';
var values = [];
$.map( source, function flattener( node ) {
if ( $.isPlainObject( node ) && node.hasOwnProperty(keyName1) && node.hasOwnProperty(keyName2) && node[keyName1] === keyValue ) {
values.push( node[keyName2] );
}
return ($.isArray( node ) || $.isPlainObject( node )) ? $.map( node, flattener) : node;
} );
return values;
}
var labels = grabKeys( cat, 'label' );
var cids = grabPairedKeys( cat, 'cid' );
You should use the push in the loop.
for(var i=0;i<ArrL.length;i++){
ArrF = ArrL[i].view;
for(var j=0;j<ArrF.length;j++){
ArrE = ArrF[j].ent;
for(var k=0;k<ArrE.length;k++){
ArrLa = ArrE[k].label;
Array.push(ArrLa);
}
}
}
Well, you only push the last value that was assigned to ArrLa after having iterated the view array. Instead, push the value right away when you encounter it:
var Array = [];
for(var i=0;i<ArrL.length;i++){
var ArrF = ArrL[i].view;
for(var j=0;j<ArrF.length;j++){
var ArrE = ArrF[j].ent;
for(var k=0;k<ArrE.length;k++){
Array.push(ArrE[k].label);
}
}
}
console.log(Array);