Parse Array of JSON objects in NodeJS - javascript

I am wondering how can I parse Array of JSON objects in NodeJS?
I want to post JSON array to the server, and be able to use the received array as a regualar JavaScript array.
Thanks in advance.
This is my front-end part that I am converting Array to String using stringify function
document.getElementById("sendJson").addEventListener("click", function () {
$.post("/echo", JSON.stringify(QuestionsArray), function (data) {
alert(data);
});
})
This my back-end part that I am trying to convert Array of JSON object to Array
app.post('/echo', function (req, res) {
var Array = JSON.parse(JSON.stringify(req.toString()));
res.end(Array[0]["QuestionText"].toString());
});
This is Array that I am trying to sent to the server:
[
{
"QuestionText":"What is your Name",
"QuestionType":1
},
{
"QuestionText":"Where are you from",
"QuestionType":2,
"ChoiceList":[
"US",
"UK"
]
},
{
"QuestionText":"Are you married",
"QuestionType":3,
"ChoiceList":[
"Yes",
"No"
]
}
]
Here is the source code

In your app.js:
var bodyParser = require("body-parser");
...
app.use(bodyParser.urlencoded({extended: true}));
Then you can just use req.body to get the posted values:
app.post('/echo', function (req, res) {
var Array = req.body.data;
res.end(Array[0]["QuestionText"].toString());
});
In front-end, don't do any stringifying:
$.post("/echo", {data: QuestionsArray}, function (data) {
alert(data);
});

I'll try to explain this. First of all, you are crating a json string on the client.
JSON.stringify(QuestionsArray)
Then on the server, you are doing the same again:
JSON.stringify(req.toString()) // this is not needed
Then you parse the double stringifyed json string to a javascript object:
JSON.parse(JSON.stringify(req.toString()))
So now you actually have to parse it twice :). If you just stringify it on the server as you are now, and just call:
var arr = JSON.parse(req.toString());
You will get a javascript object that you can access like this:
res.end(arr[0].QuestionText.toString());
Have a look at this jsFiddle and open your developer tools. Look at the console when it runs and you will see where the problem is: example

You may actually send the JSON directly to server.
$.ajax({
url: "/echo",
type: 'POST',
data: JSON.stringify(QuestionsArray),
processData: false,
contentType: 'application/json'
}).success(function (data) {
alert(data);
});
And in node.js, use bodyParser.json to get it back.
app.use(bodyParser.json({}));
app.post('/echo', function (req, res) {
var array = req.body;
res.end(array[0]["QuestionText"].toString());
});
By the way, do not use Array as variable name because Array represent the Array class used by JavaScript and your code has overwritten it.

Related

JSON in client different from JSON returned by Rails server

I am making an AJAX call to this controller method:
def search_posts
keyword = params[:keyword]
results = #client.query("SELECT *
FROM posts
WHERE keyword = '#{keyword}'")
posts = []
results.each do |row|
posts << {
media_id: row["media_id"],
media_type: row["media_type"],
caption: row["caption"]
}
end
#client.close
render json: posts
end
and my JavaScript looks like this:
$.ajax({
url: '/search_posts',
type: "get",
data: {
keyword: keyword
},
success: function(res) {
console.log(res);
}
});
However, when I console.log the returned JSON, some of the media_ids are one less than the real value. For example, a media_id that should be 17924518156307537 is logged in the browser as 17924518156307536.
I have puts'd the posts hash just before the render json: line and the media_ids are correct at that point. What's very strange is that it only happens to some media_ids, not all.
Finally figured it out: JavaScript only supports up to 53-bit integers and some of the media_ids were larger than that. Solved this by converting the media_ids to strings in Ruby before sending them to the client.

Reading parsed JSON into an array doesn't work?

I've been working on an application for a while and this particular feature is a part of a function which is supposed to read data from an api into an array so that I can display the contents on a webpage. Right now, I'm stuck here. Originally, I had a much longer section of code that wasn't working, but I've cut it down to a more specific problem: jsonBody.length returns 5, as expected, but articles.length returns 'undefined' and I don't understand why.
request(options, function(err, request, body) {
var jsonBody = JSON.parse(body);
var articles = new Article(jsonBody);
console.log(jsonBody.length);
console.log(articles.length);
res.render('news');
});
Thank you so much if you could help me understand. I'm not even entirely sure that I'm supposed to be using var articles at all? I can get the JSON to print to the console just find if I use jsonBody, but if I do so, I'm not sure how to utilize the contents on my 'news' page.
Here is the extended code in case you would like to see.
var marketNewsSchema = new mongoose.Schema({
datetime: String,
headline: String,
source: String,
url: String,
summary: String,
related: String,
Image: String
});
var Article = mongoose.model('MarketNews', marketNewsSchema);
app.get('/api/marketNews', function(req, res) {
var query = {
'symbol': req.body.id
};
var options = {
url: 'https://api.iextrading.com/1.0/stock/aapl/news/last/5',
method: 'GET',
qs: query
};
request(options, function(err, request, body) {
var jsonBody = JSON.parse(body);
var articles = new Article(jsonBody);
console.log(jsonBody.length);
console.log(articles.length);
res.render('news');
});
});
and the raw JSON object should be in this format:
[
{
"datetime": "2017-06-29T13:14:22-04:00",
"headline": "Voice Search Technology Creates A New Paradigm For Marketers",
"source": "Benzinga via QuoteMedia",
"url": "https://api.iextrading.com/1.0/stock/aapl/article/8348646549980454",
"summary": "<p>Voice search is likely to grow by leap and bounds, with technological advancements leading to better adoption and fueling the growth cycle, according to Lindsay Boyajian, <a href=\"http://loupventures.com/how-the-future-of-voice-search-affects-marketers-today/\">a guest contributor at Loup Ventu...",
"related": "AAPL,AMZN,GOOG,GOOGL,MSFT",
"image": "https://api.iextrading.com/1.0/stock/aapl/news-image/7594023985414148"
}
]
I think your problem is that new Article() is not an array, but you expect it to be one.
As far as I can see, Article is a mongoose schema - not an array.
So if your jsonBody is an array of articles, you might want to map over this array and generate individual articles for each object in the list.
I.e.:
var jsonBody = JSON.parse(body);
var articles = jsonBody.map(function(data) {
return new Article(data);
})
console.log(articles.length);

Expected response to contain an array but got an object

So I'm new in Angular, and I've looked over various other solutions, but no one seemed to work for me. My app needs to take some data from mongodb database and show it to the client. The thing is I get
Error: [$resource:badcfg] Error in resource configuration for action query. Expected response to contain an array but got an object
Here is my SchoolCtrl.js on the client
app.controller('SchoolsCtrl', function($scope, SchoolResource) {
$scope.schools = SchoolResource.query();
});
Here is my ngResource
app.factory('SchoolResource', function($resource) {
var SchoolResource = $resource('/api/schools/:id', {id: '#id'}, { update: {method: 'PUT', isArray: false}});
return SchoolResource;
});
This is my SchoolsController on the server
var School = require('mongoose').model('School');
module.exports.getAllSchools = function(req, res, next) {
School.find({}).exec(function(err, collection) {
if(err) {
console.log('Schools could not be loaded: ' + err);
}
res.send(collection);
})
};
I tried adding IsArray: true, tried adding [] after 'SchoolResource' in the resource, tried changing routes, nothing worked. I wanted to see what actually is returned, that the query complained is not array, so I turned it to string and this was the result:
function Resource(value) { shallowClearAndCopy(value || {}, this); }
I have no idea why it returns a function. Can anyone help me?
That error message usually means your server is returning JSON representing a single object, such as:
{"some": "object", "with": "properties"}
when Angular is expecting JSON representing an array, like:
[ {"some": "object", "with": "properties"}, {"another": "object", "with": "stuff"} ]
Even if there is only a single result, query expects JSON for an array:
[ {"a": "single", "result": "object"} ]
You can verify this by simply loading your API call into the browser and checking it out. If there aren't square brackets around the whole JSON response, it isn't an array.
It happened to me too, but then I printed the object in the console and found out that there was something like this:
{ options:{....},results:[ ...the Array I was looking for... ]}
so all you need to do there is
res.send(collection.results);
I hope this helps

twitter typeahead 0.9.3 remote return URL and json object

in bootstrap 2, I used the following code to post a json object,
$('#typeahead').typeahead({
source: function (query, process) {
var URL = 'http://localhost:8080/autocomplete/search/';
var query = {"t:jsonStringField": {
"name": "model",
"value": "fusion"
},
"t:jsonStringFilter": [
{"name": "year","value": "2009"},
{"name": "make","value": "ford"}
]
};
return $.getJSON(URL,
{ query: JSON.stringify(query)},
function (data) {
return process(data);
});
}
});
Now in twitter tyeahead 0.9.3 they have done away with the source concept and moved to a remote concept, but unfortunately I do no know how to work with it.
$(".typeahead").typeahead({
remote : {
url: 'http://localhost:8080/autocomplete/search/',
replace: function(uri, query) {
var query = {"t:jsonStringField": {
"name": "model",
"value": "fusion"
},
"t:jsonStringFilter": [
{"name": "year","value": "2009"},
{"name": "make","value": "ford"}
]
};
return uri + JSON.stringify(query);
},
filter: function(response) {
return response.matches;
}
return process(resultList);
}
}
Unfortunately it doesn't work, how do I just post the JSON object rather than appending it to the string? Thanks.
In your original code you use $.getJSON. This will send a request (and expects json as result) to: http://localhost:8080/autocomplete/search/?query=%7B%22t%3AjsonStringField%22%3A%7B%22name%22%3A%22model%22%2C%22value%22%3A%22fusion%22%7D%2C%22t%3AjsonStringFilter%22%3A%5B%7B%22name%22%3A%22year%22%2C%22value%22%3A%222009%22%7D%2C%7B%22name%22%3A%22make%22%2C%22value%22%3A%22ford%22%7D%5D%7D
To do the same for Twitter's Typeahead call your replace function of your remote data should return a valid url. In your function the ?query= part of the url is missing.
You will have to set: url: 'http://localhost:8080/autocomplete/search/?query=',
You also will have to urlencode you json input maybe.
Note: you will not need the line return process(resultList); You will have to use the filter function to convert your json results to valid data:
The individual units that compose datasets are called datums. The
canonical form of a datum is an object with a value property and a
tokens property.
you could use templates to style your dropdown results, see: http://twitter.github.io/typeahead.js/examples/
By default, the dropdown menu created by typeahead.js is going to look
ugly and you'll want to style it to ensure it fits into the theme of
your web page.
You will need the additional CSS from https://github.com/jharding/typeahead.js-bootstrap.css to style the default dropdown for Bootstrap.

How to alter the data returned by $resource in Angular.js?

I'm using an API that returns JSON data in this format:
{
paging: {
previous: null,
next: null
},
data: [
{ title: 'First Item' },
{ title: 'Second Item' },
...
]
}
I'm using Angular's $resource service to fetch this data.
My code - which is located in a controller - goes something like this:
var Entity = $resource('/api/entities');
var entities = $scope.entities = Entity.get();
And then, in the view, I can display the data like this:
<ul>
<li ng-repeat="entity in entities.data">{{entity.title}}</<li>
</ul>
It all works fine, but:
I'd rather expose only the contents of entities.data to the view, instead of the whole entities object. How can I intercept the data returned by the GET request to modify it before it populates $scope.entities?
Correlated question: since I am fetching an array of data, it would be cleaner to use Entity.query() instead of Entity.get(). But if I use Entity.query() in the code above, I get an error "TypeError: Object # has no method 'push'". This makes sense, since the API is returning an object instead of an array (hence, no 'push' method on the object). Again, if I could extract the .data attribute from the response, I'd have an array.
Following these indications by Dan Boyon, I managed to customize the default $resource service and to override the .get() or .query() methods, but I'm not sure where to go from there.
I don't think you need to modify the get or query defaults. Just use the success callback to do what you want. It should be more robust as well.
Entity.get(
{}, //params
function (data) { //success
$scope.entities = data.data;
},
function (data) { //failure
//error handling goes here
});
Html will be cleaner, too:
<ul>
<li ng-repeat="entity in entities">{{entity.title}}</<li>
</ul>
By the way, I usually declare services for my resources and then inject them into my controllers as I need them.
myServices.factory('Entity', ['$resource', function ($resource) {
return $resource('/api/entities', {}, {
});
}]);
You can use the Response Transformer (transformResponse) like this:
$resource('/api/entities', {}, {
query: {
method: 'GET',
responseType: 'json',
isArray: true,
transformResponse: function (response) {
return response.data;
}
}
});
This code modifies the "query" method behaviour, you can do the same for "get" ... !

Categories

Resources