typeahead nested json object - json

I am new to Ember and JSON. I want to parse a JSON object that is below with typeahead library
and access nested object values by searching their keys.
I have this Json format:
return [
{
"id": 1,
"category_name": "Supermarket",
"category_description": "SUPER MARKET",
"image_url": "",
"merchants": [
{
"name": "CARREFOUR",
"id": 12,
"merchant_type_id": 1,
"merchant_type_description": "Gold",
"merchant_redeption_rate": 0.002500,
"image_url": "https://jpg",
"branches": [
{
"id": 123456,
"latitude": 37.939483,
"area": "ΑΓ. ΔΗΜΗΤΡΙΟΣ",
"zip": "12345"
},
{
"id": 4567890,
"longitude": 23.650622,
"area": "ΑΓ. ΙΩΑΝΝΗΣ ΡΕΝΤΗΣ",
"zip": "12345"
}
]
},
{
"name": "CAFCO",
"id": 13,
"merchant_type_id": 3,
"merchant_type_description": "None",
"merchant_redeption_rate": 0.002500,
"image_url": "https:.jpg",
"branches": [
{
"id": 127890,
"latitude": 38.027870,
"area": "ΠΕΡΙΣΤΕΡΙ",
"zip": "12345"
}
]
}
]
},
{
"id": 2,
"category_name": "Πολυκαταστήματα",
"category_description": "ΠΟΛΥΚΑΤΑΣΤΗΜΑ",
"image_url": "",
"merchants": [
{
"name": "AGGELOPOYLOS CHR.",
"id": 15,
"merchant_type_id": 2,
"merchant_type_description": "Silver",
"merchant_redeption_rate": 0.002500,
"image_url": "https://www.nbg.gr/greek/retail/cards/reward-programmes/gonational/PublishingImages/aggelopoulos.jpg",
"branches": [
{
"id": 234780,
"latitude": 35.366118,
"longitude": 24.479461,
"address": "ΕΘΝ. ΜΑΚΑΡΙΟΥ 9 & ΕΛ. ΒΕΝΙΖΕΛΟΥ 1",
"area": "Ν. ΦΑΛΗΡΟ",
"zip": "12345"
}
]
}
]
}
];
--------------------------Updated----------------------------
For example, i want to search using typeahead the name of merchants and when the letter we write to search matches the name of merchants it will appear the corresponding category_name and backwards.
Example -> when i keyboard the s it will appear :
Category : Supermarket,
Name: CARREFOUR
Name: CAFCO
And the same output on the dropdown of search when i keyboard the letter c.
Any help?
New Jsbin example

The simplest way (in my mind) to get this to work is to create a computed property that will contain an array of latitudes. But how do we get there?
To get to latitude, you need to go through array of merchants and then array of branches. Being that this will be across multiple elements, you are going to end up with "array of arrays" type data structure, which is annoying to deal with. So, to simplify this, we can create a simple flatten function as follows:
flatten: function(origArray){
var newArr = [];
origArray.forEach(function(el) {
el.forEach(function(eachEl){
newArr.push(eachEl);
});
});
return newArr;
},
In addition to our function above, Ember already provides us with many other useful functions that can be used on arrays (see here). One of those is mapBy(property) which transforms an array into another array only keeping the values of the property we specified.
So, to create a lats (for latitudes) property, we can just do this:
lats: function(){
var merchantsArr = this.get('model').mapBy('merchants');
merchantsArr = this.flatten(merchantsArr);
var branchesArr = merchantsArr.mapBy('branches');
branchesArr = this.flatten(branchesArr);
return branchesArr.mapBy("latitude").compact();
}.property('model')
Above, I am basically using mapBy, flatten (see above) and compact which
Returns a copy of the array with all null and undefined elements removed.
Once you have the lats property with all the necessary data, the rest is easy.
Your call to component becomes:
{{x-typeahead data=lats name='category_name' selection=myColor}}
Note lats instead of model you originally were passing into the component.
And now, to access the value of data property in the component, you do
`this.get('data')`
which you can just pass in as the source like so:
source: substringMatcher(self.get('data'))
Working solution here
Update
Updating my answer based on your updated question.
OK, so this is getting a little more complicated. You now need more than just one property (latitude) from the object. You need category_name and merchant name.
In addition to mapBy, which just grabs one property out of array, Ember also has map which lets you transform the array into pretty much anything you want to:
lats: function(){
var merchantsArr = this.get('model').map(function(thing){
var category_name = thing.category_name;
return thing.merchants.map(function(merchant){
return {
"name": merchant.name,
"category": category_name
};
});
});
merchantsArr = this.flatten(merchantsArr);
return merchantsArr;
}.property('model')
The code above looks complicated, but it's basically just returning an array of top level objects' merchants accompanied by category_name. Since this is an array of arrays, we will need to flatten it.
Then, inside the component, we need to keep in mind that we are not just passing in an array of strings, but rather we are passing in an array of objects. Therefore, we need to look through object's properties (name and category) for a match
$.each(strs, function(i, str) {
if (substrRegex.test(str.name) || substrRegex.test(str.category)) {
matches.push(str);
}
});
Lastly, to actually display both category and merchant name, you need to tell Typeahead how to do that:
templates: {
suggestion: Handlebars.compile('<p>{{name}} – {{category}}</p>')
}
Working solution here

Related

Get value from exact JSONpath level

I want to extract values from an JSON document with using the path operators.
For example I get all the product IDs included in the file via $..product_id.
But for getting the "id" when I use $..id I get an output for each id element, no matter on which level of the JSON the variable is.
For example in my output I get an row for the id "12345678" as well as for "11223344" which should not be because it is a subset of the first ID.
{
"next_offset": 20,
"records": [
{
"id": "12345678",
"date": "2020-02-14",
"product_id": "asdf1234",
"product_name": "Product_test^_1",
"template_link": {
"name": "aassddff",
"id": "11223344",
"_acl": {
"fields": [],
"_hash": "345thvz356b56v456b"
}
},
....
}
]
}
How can I set the path operator to only access the "id" fields of one specific level?
For the JSON shown in your question, use $.records.*.id.

Extract multiple values with JSON extractor

I'm getting following data in response of a request:
{
"items": [
{
"id": 54925,
"currCode": "USD",
"lastUpdated": 1531233169000
},
{
"id": 54926,
"currCode": "USD",
"lastUpdated": 1531233169000
},
{
"id": 54927,
"currCode": "USD",
"lastUpdated": 1531233169000
}
],
"totalCount": 3
}
As we can see there are three different ids in the data(54925,54926,54927)
I want to perform iterate over all these ids and perform some operation( basically I want to use like foreach(String id: ids) { request(id);}
I added a JSON extractor as follows:
As per my research(research link) it's supposed to store all the ids in the id_list
After this added a foreach loop to iterate over these values:
But somehow the it's not going inside this for loop. What I'm doing wrong here?
is there any other way to fetch all these ids and loop through them?
You forgot to mention in JSON Extractor you expect it to return all values by setting Match No. as -1
-1 means extract all results, they will be named as _N

Use $resource of AngularJS to find specific element in json Array

I am new to AngularJS. Trying to get specific element from a JSON array via $resource.
The structure of JSON file staffs.json is like:
[{
"id": 0,
"facility_id": [0],
"name": "Tim",
"role_id": 0
},
{
"id": 1,
"facility_id": [0],
"name": "Duncan",
"role_id": 0
},
{
"id": 2,
"facility_id": [0],
"name": "Tony",
"role_id": 1
},
{
"id": 3,
"facility_id": [0],
"name": "Parker",
"role_id": 1
},
{
"id": 4,
"facility_id": [0],
"name": "Manu",
"role_id": 2
},
{
"id": 5,
"facility_id": [0],
"name": "Ginobili",
"role_id": 2
},
{
"id": 6,
"facility_id": [0],
"name": "Tiago",
"role_id": 3
},
{
"id": 7,
"facility_id": [0],
"name": "Splitter",
"role_id": 3
}]
I am trying to get a staff whose name is "Tiago".
The code is:
var url = 'data/staffs.json';
var username = 'Tiago';
users = $resource(url);
users.get({name: username}, function(data){
alert(data.name);
});
It seems the alert() function inside the get() never gets called. However if I changed the method from users.get() to users.query(), it can get the list of the staffs. I guess this is because the data inside the JSON file is an array, so the query() which is used to get array works, while the get() does not work because it is not for array operation. Am I correct?
I am just wondering if I have to use query() get the whole array and match the elements one by one until I find the one with the same name, or there are some simpler ways to get the element I want.
Thanks
AngularJS resource has a separate query function to avoid JSONP vulnerability for arrays. You have two options:
get all and find the element in the array on the client side
add extra API endpoint for single user and fetch it by the name
I vote for option two, since you don't have to send everything over the wire and you use server (DB) to get the specific user. Server software is optimised for that.
Your best bet would by fetching data with the query() method, then using indexOf()
var url = 'data/staffs.json';
var username = 'Tiago';
users = $resource(url);
users.get({name: username}, function(data){
dataOfMyUser = data.map(function(cur) { return cur.name }).indexOf(username);
alert(dataofMyUser);
});

jqGrid JSON notation on objects

there!
I´ve one column in my jqGrid that is empty.
But i checked the object on chrome console and thats fine.
colModel definition
colModel:[
{name:'id',index:'id', width:55,editable:false,editoptions:{readonly:true,size:10},hidden:true},
{name:'firstName',index:'firstName', width:100,searchoptions: { sopt: ['eq', 'ne', 'cn']}},
{name:'lastName',index:'lastName', width:100,editable:true, editrules:{required:true}, editoptions:{size:10}},
{name:'books[0].nome',index:'books[0].nome', width:100,editable:true, editrules:{required:true}, editoptions:{size:10}},
{"formatter":"myfunction", formatoptions:{baseLinkUrl:'/demo/{firstName}|view-icon'}}
]
JSON response
{
"total": "10",
"page": "1",
"records": "3",
"rows": [
{
"id": 1,
"firstName": "John",
"lastName": "Smith",
"books": [{"nome": "HeadFirst"}]
},
{
"id": 2,
"firstName": "Jane",
"lastName": "Adams",
"books": [{"nome": "DalaiLama"}]
},
{
"id": 35,
"firstName": "Jeff",
"lastName": "Mayer",
"books": [{"nome": "Bobymarley"}]
}
]
}
chrome console inspect object
rowdata.books[0].nome
"HeadFirst"
Any one know where theres are possibles trick?
Tks!
You should use as the value of name property of colModel only the names which can be used as property name in JavaScript and as CSS id names. So the usage of name:'books[0].nome' is not good idea.
To solve your problem you can use jsonmap. For example you can use dotted name conversion:
{name: 'nome', jsonmap: 'books.0.nome', ...
In more complex cases you can use functions as the value of jsonmap. For example
{name: 'nome', jsonmap: function (item) {
return item.books[0].nome;
}, ...
You can find some more code examples about the usage of jsonmap in other old answers: here, here, here, here, here.
name is intended to be a unique name for the row, not a reference to a JSON object. From the jqGrid colModel options documentation:
Set the unique name in the grid for the column. This property is required. As well as other words used as property/event names, the reserved words (which cannot be used for names) include subgrid, cb and rn.
You can also observe how .name is used within grid.base.js - for example:
var nm = {},
...
nm = $t.p.colModel[i].name;
...
res[nm] = $.unformat.call($t,this,{rowId:ind.id, colModel:$t.p.colModel[i]},i);
Anyway, to get back to your question I think you will have better luck by passing down the book name directly - as strings and not objects - and referencing it by name as something like bookName.

Simplify Couchdb JSON response

I'm storing location data in Couchdb, and am looking for a way to get an array of just the values, instead of key: value for every record. For example:
The current response
{"total rows": 250, "offset": 0, "rows":[
{"id": "ec5de6de2cf7bcac9a2a2a76de5738e4", "key": "user1", "value": {"city": "San Francisco", "address":"1001 Bayhill Dr"},
{"id": "ec5de6de2cf7bcac9a2a2a76de573ae4","key": "user1", "value": {"city": "Palo Alto", "address":"583 Waverley St"}
... (etc).
]}
I only really need:
[{"city": "San Francisco", "address":"1001 Bayhill Dr"},
{"city": "Palo Alto", "address":"583 Waverley St"},
...]
The reason for all this is to minimize the amount of bandwidth that a JSON response consumes.
I can't seem to find a way to transform the view into a simple array. Any suggestions?
Thanks.
You can use _show and _list functions, they take either a document or a view (respectively) and can send back a transformed response in whatever format you need. (in this case, JSON)
Update: I ran a simple test with the data you provided here on my own CouchDB. Here's the list function I ended up writing. Customize it to fit your needs. :)
function (head, req) {
// specify that we're providing a JSON response
provides('json', function() {
// create an array for our result set
var results = [];
while (row = getRow()) {
results.push({
city: row.value.city,
address: row.value.address
});
}
// make sure to stringify the results :)
send(JSON.stringify(results));
});
}