I am trying to write a basic, experimental search system using JavaScript and JSON, with the searchable data contained in the JSON file. Multiple 'posts' are listed in the file, and each post has an array of 'tags'. My intent is to search through each posts tags, and retrieve only the posts that have tags matching a query, such as "funny cat video" (the posts would have to have all three tags, "funny", "cat", and "video", to be returned).
My particular concern is performance. I am sure that this technique will be inefficient, as there are approximately 2000 posts, and each one has from 5 to 50 tags, but it has to be done with JavaScript. I am already referencing from this website on how to maximise performance, though I could do with some extra help.
Here is my code so far for storing the data:
{
"index": {
"count": "2",
"posts": [
{
"id": "1",
"date": "2014-11-21 17:16:39 GMT",
"url": "http://url/",
"image": "http://big_image/",
"thumbnail": "http://little_image/",
"tags": ["funny", "cat", "picture", "falling", "chair", "window sill", "funny"]
},
{
"id": "2",
"date": "2014-11-20 17:57:32 GMT",
"url": "http://url1/",
"image": "http://big_image1/",
"thumbnail": "http://little_image1/",
"tags": ["funny", "cat", "picture", "jumping", "water", "bath", "funny"]
}
]
}
}
And this is my Javascript:
var query = "funny cat bath".split(" ");
var data = JSON.parse("THE JSON GOES HERE");
var count = data.index.count;
var index = data.index.posts;
for (var i = 0, indexLength = index.length; i < indexLength; i++) {
tags = index[i].tags;
for (var q = 0, queryLength = query.length; q < queryLength; q++) {
if(tags.indexOf(query[q]) !== false) {
console.log(index[i]);
}
}
}
Unfortunately, I can't figure out how to get it to return only the posts that have all three tags, and it returns all posts with any of the tags supplied. Not only that, but it returns duplicates.
Does anybody have a better solution? I'm stuck.
You need to use a flag and only "write" out the match when they are all found, you are writing it out when one is found. Plus indexOf returns -1, not false. Basic idea below:
var data = {
"index": {
"count": "2",
"posts": [
{
"id": "1",
"date": "2014-11-21 17:16:39 GMT",
"url": "http://url/",
"image": "http://big_image/",
"thumbnail": "http://little_image/",
"tags": ["funny", "cat", "picture", "falling", "chair", "window sill", "funny"]
},
{
"id": "2",
"date": "2014-11-20 17:57:32 GMT",
"url": "http://url1/",
"image": "http://big_image1/",
"thumbnail": "http://little_image1/",
"tags": ["funny", "cat", "picture", "jumping", "water", "bath", "funny"]
}
]
}
};
var query = "funny cat bath".split(" ");
var filteredSet = []; //where the matched objects will reside
var posts = data.index.posts; //get the posts
for (var i=0; i<posts.length;i++) { //loop through the posts
var post = posts[i];
var tags = post.tags; //reference the tags
var hasMatch = true; //flag to hold the state if we have a good match - set to true by default
for (var j=0; j<query.length; j++) { //loop through the tags the user is looking for
var index = tags.indexOf(query[j]); //look for it in the set [Note older IEs needs polyfill see MDN for code]
if (index===-1) { //indexOf returns -1 if not found
hasMatch=false; //set Boolean flag so we do not record item
break; //exit loop - no reason to keep checking
}
}
if (hasMatch) { //if we found all the tags
filteredSet.push(post); // add to the filtered set
}
}
console.log(filteredSet); //show the filtered set
Related
I am currently trying to send a user information about a JSON object that I've recieved from an API. An example of the format is
[
{
"lang_code": "eng",
"site_language": "1",
"name": "English"
},
{
"lang_code": "afr",
"site_language": "1",
"name": "Afrikaans"
},
{
"lang_code": "ale",
"site_language": "0",
"name": "Aleut"
},
]
I want to be able to access the lang_code property of every single language and send it. I've tried to use
var languageCodes;
var languageResult = body.lang_code; //body is the result from a request.get({ ... })
for(var codes in languageResult) {
languageCodes = languageResult[codes];
}
Object.keys does nothing, as it just sends 72 numbers to me. Any thoughts?
On a side note, I also want people to be able to type "! languages [my command] eng", for example, and it sends "English" instead of just sending "1 is [object Object]".
Assuming body is the array at the top of your question, if you just want an array of all the language codes, this should suffice
var languageCodes = body.map(function(lang) {
return lang.lang_code;
});
var body = [{
"lang_code": "eng",
"site_language": "1",
"name": "English"
}, {
"lang_code": "afr",
"site_language": "1",
"name": "Afrikaans"
}, {
"lang_code": "ale",
"site_language": "0",
"name": "Aleut"
}];
var languageCodes = body.map(function(lang) {
return lang.lang_code;
});
document.getElementById('out').innerHTML = JSON.stringify(languageCodes);
<pre id="out"></pre>
I looped through your lang_codes like this:
var codes = [{"lang_code":"eng","site_language":"1","name":"English"}, {"lang_code":"afr","site_language":"1","name":"Afrikaans"},{"lang_code":"ale","site_language":"0","name":"Aleut"}];
for(var i = 0; i < codes.length; i++) {
console.log(codes[i].lang_code);
}
I have an object in which I used JSON Stringify with to view its contents like so:
var testing = JSON.stringify($scope.test, null, 4);
And the object looks like this when i do console.log(testing):
{
"_id": "53e866a8a595b7041f9510c9",
"start": "2014-08-04T07:00:00.000Z",
"end": "2014-08-16T07:00:00.000Z",
"location": "Australia",
"name": "Joe's Surprise",
"__v": 1,
"array": [
{
"_id": "53ddc8c98ae4813c0420e189",
"provider": "local",
"name": "Test User",
"username": "testUser",
"email": "test#test.com",
"hashedPassword": "e5ri7OVhzNQMZpSqxnB3p2FyrpxskFE3yM8jHn5hfzZZvdd57YhhJrjFWJqBQhhyZz6y8UG68mr+rQ95admtfw==",
"salt": "PVEFtMfyJ/7TX9Do0cYMdQ==",
"__v": 2,
"attending": [
"53e866a8a595b7041f9510c9"
],
"role": "user"
},
]
}
however, I want to print out the username attribute within the array attribute of variable testing but I am unable to do so. I've tried doing a for loop like so:
for(var i = 0; i < testing.array.length; i++){
console.log(testing.array[i].username);
}
But the .length attribute is considered undefined. I've also tried simply doing console.log(testing._id) to see if that works but this returns undefined. I'm not sure what I'm doing wrong, can anyone help? Thanks!
var testing = JSON.stringify($scope.test, null, 4);
is converting $scope.test into a string (presumably so you can view in a human readible format). A string contains no arrays or properties. You want it in its original form, not in a string.
you probably want:
for(var i = 0; i < $scope.test.array.length; i++){
console.log($scope.test.array[i].username);
}
Below is my json code:
{
"uID": "4564646",
"favorites": [
{ "name" : "my store",
"id" : "87654321",
"items":
[
{
"productID": "46565",
"title": "Project",
"type": "Weekend Project"
},
{
"productID": "112",
"title": "Bathroom",
"type": "Weekend Project"
},
{
"productID": "785",
"title": "link",
"type": "main Project"
}
]
}
]
}
Now i want to check the PRODUCTID for each and delete the entry from items which matches my product id 112 .
I want to use javascript only, the array items is not fixed and also Do i have to parse the json before applying the deletion method.
var obj = JSON.parse(json_string);
var fav_items = obj.favorites[0].items;
for (var i = fav_items.length - 1; i >= 0; i--) {
if (fav_items[i].productID == 112) {
fav_items.splice(i, 1);
}
}
Note that you need to do the loop backwards, because when you splice out an element from the array, all the elements after it get there indexes shifted down. If you do a normal upward loop, you'll skip over the elements after the ones you delete.
Just do:
for (var i = 0; i < data.favorites[0].items.length; i++) {
if (data.favorites[0].items[i].productID != 112) {
data.favorites[0].items.splice(i, 1);
i--; //DONT FORGET THIS
}
}
splice can remove array elements - dont forget the i-- though when splicing in a loop as the array has the potential to shorten with each iteration.
I know there's plenty of answers on this and most are suggesting looping thru the object, returning what you need, I'm not sure this is the best approach, in my case anyway.
What I have is array with entries referencing to another array people(with id and name) by person_id and projects(with id and name) by project_id.
What I need is to be able to access project and person with a particular id inside the loop on entries, so I can get their names. Doing what others have suggested I'd loop thru people and projects inside each irritation of entries, which seems like awful lot of looping.
So I thought I'd make something I called a "hashtable" from both people and projects on init, which means pretty much creating a new objects people_hashtable and projects_hashtable where key would be the id
so
[
{
"id": "8",
"name": "John Doe"
}
]
would became
{
"8": {
"name": "John Doe"
}
}
this way I'd have easy access to the name without looping all the time while still maintaining the old array with its original order(that's why I'm not outputting it this way directly from server, you can't quite order an object and I'm using both people and projects in a selectbox, which needs to be ordered by name).
Am I doing it right? Are there better way? Or should I forget this completely and stick with the search loop as suggested in other question?
I'm trying to be as efficient as possible on both server and client side.
You basically doubled all the objects just to avoid loop. So, unless you have some bad performance issues, I would avoid that.
In case you really, really need a kind of hashmap, I would prefer storing the array's index instead of another copy of the object:
// array
var arr = [
{
"id": "8",
"name": "John Doe"
}
];
// lookup table
var lookup = {
"8": 0
}
Of course doing that, means you can't modifying the array's without rebuild the hashmap.
Generate it's quite simple:
var lookup = arr.reduce(function(lookup, item, index) {
lookup[item.id] = index;
return lookup;
}, {});
You can also use that to generate the object you mentioned your question:
var lookup = arr.reduce(function(lookup, item) {
lookup[item.id] = {name: item.name};
return lookup;
}, {});
But as I said it's something I would avoid.
Following code may help you. JSFIDDLE
var arr = [
{
"id": "8",
"name": "John Doe"
}
];
var obj = {};
for(var i=0; i< arr.length; i++){
obj[arr[i].id] = {name: arr[i].name};
}
console.log(obj);
var articles= {
"item1":{
"id":"155",
"name":"First Item",
"value":-5199.6
},
"item2":{
"id":"255",
"name":"Second Item",
"value":-424.91
}
}
var ids = [];
for(var item in articles) {
ids.push(articles[item]['id']);
}
console.log(ids);
This lib https://github.com/paularmstrong/normalizr makes it pretty easy to do. Both normalization and denormalization.
It can turn this
{
"id": "123",
"author": {
"id": "1",
"name": "Paul"
},
"title": "My awesome blog post",
"comments": [
{
"id": "324",
"commenter": {
"id": "2",
"name": "Nicole"
}
}
]
}
into this
{
result: "123",
entities: {
"articles": {
"123": {
id: "123",
author: "1",
title: "My awesome blog post",
comments: [ "324" ]
}
},
"users": {
"1": { "id": "1", "name": "Paul" },
"2": { "id": "2", "name": "Nicole" }
},
"comments": {
"324": { id: "324", "commenter": "2" }
}
}
}
and the other way around.
I have some JSON data which is in the following format:
[
{
"id": 145,
"Name": "John",
"company_name": "A",
"email": "john#gmail.com",
"country": "USA"
},
{
"id": 500,
"Name": "Mike",
"company_name": "B",
"email": "mike#gmail.com",
"country": "London"
},
{
"id": 100,
"Name": "Sally",
"company_name": "C",
"email": "sally#gmail.com",
"country": "USA"
}
]
Now, suppose I ask the user to enter an id, say 100. Then I need to display all the details for this id.
I am supposed to do this as a part of a web application,where I have to invoke an display the fields of a particular id. This would have been easy if I had a hash like implementation and could display all parameters based on the key-id.
Can anybody tell me how this can be done using such kind of data?
Thanks!
You could use something like this:
(Assuming the you have a variable data with your Json Object).
function getid(id) {
var nobj;
data.forEach(function(obj) {
if(obj.id == id)
nobj = obj;
});
return nobj
}
var neededobj = getid(100);
console.log(neededobj.Name + "\n" + neededobj.email + "\netc...");
But to get the Object you have to loop through your complete array,
until it finds the right Object
see this Fiddle
I think you are looking for Associative Array,
the simplex one would be,
var associativeArray = [];
associativeArray["one"] = "First";
associativeArray["two"] = "Second";
associativeArray["three"] = "Third";
alert(associativeArray.one);
And obviusly you can add json object in value place