I think I'm going crazy... I'm just trying to do some basic API learning for NodeJS and I've got this, which works fine and prints "United States Dollar" to console...
app.get("/", function(req, res){
const url = "https://api.coindesk.com/v1/bpi/currentprice.json"
https.get(url, function(response){
console.log(response.statusCode);
response.on("data", function(data){
const priceData = JSON.parse(data);
console.log(priceData.bpi.USD.description);
})
})
but when I'm trying to access it by using the array position of USD (which is [0])like this...
app.get("/", function(req, res){
const url = "https://api.coindesk.com/v1/bpi/currentprice.json"
https.get(url, function(response){
console.log(response.statusCode);
response.on("data", function(data){
const priceData = JSON.parse(data);
console.log(priceData.bpi[0].description);
})
})
I get a crash of ...
TypeError: Cannot read property 'description' of undefined
The JSON is
{
"time": {
"updated": "Oct 21, 2021 16:10:00 UTC",
"updatedISO": "2021-10-21T16:10:00+00:00",
"updateduk": "Oct 21, 2021 at 17:10 BST"
},
"disclaimer": "This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org",
"chartName": "Bitcoin",
"bpi": {
"USD": {
"code": "USD",
"symbol": "$",
"rate": "63,222.0050",
"description": "United States Dollar",
"rate_float": 63222.005
},
"GBP": {
"code": "GBP",
"symbol": "£",
"rate": "45,779.4964",
"description": "British Pound Sterling",
"rate_float": 45779.4964
},
"EUR": {
"code": "EUR",
"symbol": "€",
"rate": "54,306.7540",
"description": "Euro",
"rate_float": 54306.754
}
}
}
The USD object is position[0] of the bpi array (right?) so why can't I just tap into it like above? This example seems pretty similar to mine so can't see where I'm going wrong?
The problem is the content of priceData.bpi is not an array [], it's an object {}, so you can't access USD by position, the only way to access it is priceData.bpi.USD.
More about JS arrays, objects.
However, if you really need to access it by position, you can convert the contents of priceData.bpi into an array using the Object.entries() method.
Example
let priceData = {"time":{"updated":"Oct 21, 2021 16:39:00 UTC","updatedISO":"2021-10-21T16:39:00+00:00","updateduk":"Oct 21, 2021 at 17:39 BST"},"disclaimer":"This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org","chartName":"Bitcoin","bpi":{"USD":{"code":"USD","symbol":"$","rate":"63,340.4233","description":"United States Dollar","rate_float":63340.4233},"GBP":{"code":"GBP","symbol":"£","rate":"45,865.2439","description":"British Pound Sterling","rate_float":45865.2439},"EUR":{"code":"EUR","symbol":"€","rate":"54,408.4735","description":"Euro","rate_float":54408.4735}}}
let bpiArr = Object.entries(priceData.bpi)
console.log(bpiArr[0][1].description)
Note: the first [0] element of bpiArr[0] contains the string "USD" and the second [1] contains an object which got the description key and its value.
More information
bpi is not an Array but an object. If it uses curly brackets it is an object. If using square brackets it is an array. To access the USD property of bpi object you use dot notation (like you have done: bpi.USD) or you use bpi["USD"]
Based on your JSON bpi is an object but you are accessing it via array index which is wrong. If you want the value of USD, the way you were accessing in the first snippet is correct. However, if you want to use it as an array, you can do like below:
const {bpi= {}} = json;
const bpiArr = Object.entries(bpi);
// to access all the values
for (const [key,val] of bpiArr) {
console.log(key,val.description)
}
Related
I'm new to Node.js/AWS lambda. Ive successfully created several documentClient QUERY functions that return a single or multiple item JSON Document in this format:
[
{
"name": "andy",
"color": "purple",
"snack": "oreos"
}
]
When I use documentClient GET and get back my single record its in THIS format, which is not playing well with the client code (apple / ios swift)
{
"name": "andy",
"color": "purple",
"snack": "oreos"
}
I'm hopign i can change the format returned from documentClient.get() to include the fill JSON document format including leading and trailing brackets .. []
I am a node.js & aws.lambda and documentClient novice, so apologies if this is a very basic question....
provided in above text
If I understood well, you're receiving an object instead of a array.
You can use the scan function to retrieve an array of results:
var params = {
TableName : 'Table',
FilterExpression : 'Year = :this_year',
ExpressionAttributeValues : {':this_year' : 2015}
};
var documentClient = new AWS.DynamoDB.DocumentClient();
documentClient.scan(params, function(err, data) {
if (err) console.log(err);
else console.log(data);
});
Or you can transform the result to array:
const document = await documentClient.get({
TableName: "table-of-example",
Key: {
id: "id-of-example"
}
});
return [data]
Please read the document to understand more how the document dynamodb sdk works: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#scan-property
I want to fetch countries and cities from my front end, but I know first, I need to make a server-side script on the backend to be able to do so.
If geography is a mock package where I can do so, and this is the code I have thus far, how could I prepare my backend to receive these fetch requests?
app.get('/:locations', function (req, res) {
Geography.init().then(function() {
console.log(Geography)
Geography.open(req.params.url).then(function(site) {
console.log(Geography)
site.analyze().then(function(results) {
res.json(results)
})
})
})
})
Would it look something like this? (incomplete, of course....)
select
countries
cities
Taking the library I used as an example in the comments:
In the example provided in the readme, a JSON reponse is returned of an array of cities matching the filter (or close to it) such as [{}, {}, {}, ...]
So, if you wanted to form a response from this, you could just take some of the data. For example, if you wanted to return the country along with a latitude and longitude you could do:
// let "cities" be the JSON response from the library
// cities[0] is the first object in the array from the response
res.json({
"country": cities[0].country,
"location": {
"lat": cities[0].loc[1], //longitude comes first
"lon": cities[0].loc[0]
}
});
You could implement this with your GET endpoint like:
app.get('/:locations', function (req, res) {
cities = citiesLibrary.filter(city => city.name.match(req.params.locations));
});
But if you wanted to return all the results returned by the library then you could simply just use:
res.json(cities);
I'm trying to get records with a date between two dates (provided by URL). A am using Lodash and Moment. I tried it in the following way but the result is empty. Does somebody have any idea? Thank you.
app.get('/paymentListByDate/:from/:to/', (req, res) => {
let response = getDataPayment();
let from_url = req.params.from;
let to_url = req.params.to;
let dateFormat = "DD-MM-YYYY";
let filtered = _.filter(response, { 'dueDate': moment().isBetween(moment(from_url, dateFormat), moment(to_url, dateFormat))});
sendDelayedResponse(res, filtered, 1);
});
sendDelayedResponse() method should be fine. Parameters as well. JSON object is the following:
{
"value": {"amount": 1000, "currency": "CZK"},
"partyAccount": {"prefix": "035", "accountNumber": "123456789", "bankCode" :"2010"},
"dueDate": "15.01.2020",
"recurringPayment": {"firstPayment": "First payment", "lastPayment": "Last payment", "interval": "WEEK"},
"payeeMessage": "Message2",
"payerMessage": "Message1",
"categoryId": 0,
"additionalInfo": {"constantSymbol": "123456789", "variableSymbol": "123456789", "specificSymbol": "123456789"},
"id": 1,
"accountId": 123456789,
"editableByUser": true,
"realizationStatus": "RTS_REALISED"
}
moment() returns current date time. You have to compare from_url with to_url (I don't know why you use _url instead of _date).
filter just working with a collection, I hope getDataPayment() returns a array in any cases.
Without lodash:
const filtered = response.filter((o) => {
return moment(o.dueDate, 'DD.MM.YYYY') // Convert to moment with exactly date format
.isBetween(moment(from_url, dateFormat), moment(to_url, dateFormat));
});
with lodash:
const filtered = _.filter(response, (o) => {
return moment(o.dueDate, 'DD.MM.YYYY')
.isBetween(moment(from_url, dateFormat), moment(to_url, dateFormat));
});
I have the next response:
{
"Status": 200,
"Email": "aristos#gmail.com",
"Values": "[\"{\\\"name\\\":\\\"John\\\",\\\"age\\\":30,\\\"ids\\\":[ \\\"123445\\\", \\\"2345456\\\", \\\"42346\\\" ]}\"]"
}
I want to fix this part:
"Values": "[\"{\\\"name\\\":\\\"John\\\",\\\"age\\\":30,\\\"ids\\\":[ \\\"123445\\\", \\\"2345456\\\", \\\"42346\\\" ]}\"]"
So it looks better like this:
{ Status: 200,
Email: 'aristos#gmail.com',
Values: '{"name":"John","age":30,"ids":[ "123445", "2345456", "42346" ]}' }
I'm using node js.
var result={Status: 200,
Email: req.body.email,
Values: req.body.values};
The request is :
email:aristos#gmail.com
values:{"name":"John","age":30,"ids":[ "123445", "2345456", "42346" ]}
a post call
Regards
If you need to use req.body.values is better to use the JSON.parse() method like this:
var val = JSON.parse(req.body.values);
And then your final response String should be stringify using the JSON.stringify() method:
var result={Status: 200,
Email: "email#example.com",
Values: val};
const response = JSON.stringify(result);
Please take a look of this jsfiddle.
Not sure why your data is wrapped into array and stringified, but that's another story.
So, you need to parse a json string, and get 1st array element. Like this:
const response = {
"Status": 200,
"Email": "aristos#gmail.com",
"Values": "[\"{\\\"name\\\":\\\"John\\\",\\\"age\\\":30,\\\"ids\\\":[ \\\"123445\\\", \\\"2345456\\\", \\\"42346\\\" ]}\"]"
};
// now it's parsed and unescaped like - {"name":"John","age":30,"ids":[ "123445", "2345456", "42346" ]}
const values = JSON.parse(response.Values)[0];
response.Values = values;
// From now 'response' object will be as you want
I''m really new to Node but I currently have a NodeJS / Express open source CMS and would like to output some API data for an app that I am working. Forgive me if I'm not using the correct terminology or whatnot, this is new to me.
What I currently have are two collections, locations and tours. The CMS allows me to create a relationship between the two. This simply stores an array of ObjectID's in the locations record for each associated tour record.
What I want to do is take my API output code (below) and have it output the entire tours array, complete with all the fields (title, description, etc), in with each location record. Currently it only outputs an array of the ID's.
Here is my current code:
var async = require('async'),
landmark = require('keystone');
var Location = keystone.list('Location'),
Tour = keystone.list('Tour');
/**
* List Locations
*/
exports.list = function(req, res) {
Location.model.find(function(err, items) {
if (err) return res.apiError('database error', err);
res.apiResponse({
locations: items
});
});
}
/**
* Get Location by ID
*/
exports.get = function(req, res) {
Location.model.findById(req.params.id).exec(function(err, item) {
if (err) return res.apiError('database error', err);
if (!item) return res.apiError('not found');
res.apiResponse({
location: item
});
});
}
Current API output (truncated):
{
"locations": [
{
"_id": "53a47997ebe91d8a4a26d251",
"slug": "test-location",
"lastModified": "2014-06-20T20:19:14.484Z",
"commonName": "test location",
"__v": 3,
"url": "",
"tours": [
"53a47963ebe91d8a4a26d250"
],
"images": []
}
]
}
What I'm looking for:
{
"locations": [
{
"_id": "53a47997ebe91d8a4a26d251",
"slug": "test-location",
"lastModified": "2014-06-20T20:19:14.484Z",
"commonName": "test location",
"__v": 3,
"url": "",
"tours": [
{
"_id": "53a47963ebe91d8a4a26d250",
"title": "my test tour title",
"url": "url_to_audio_file"
}
],
"images": []
}
]
}
Anyone know if this is possible? Any help would be appreciated! Thanks!
It looks like you have setup your Location model to have a reference to the Tours, defined as an array of Tours. This means that when you store the Tour within your Location, you're not storing the data that represents that Tour, but instead an ID that references the Tour. When you perform the find operation, you're seeing that in the response that you send back to the client.
If this is the case, then you might want to take a look at Mongoose's populate function. This will take those references and populate them fully with the data that they contain.
So for instance, you can change your query to the following:
Location.model.find().populate('tours').exec(function(err, items) {
// items should now contain fully populated tours
}
Let me know if this isn't what you mean and I can try to help further.
The solution provided by #dylants is absolutely correct. However, for it to work you need to have tours declared as a Types.Relationship field in your Location list with the ref option set to Tour.
Check out the Keystone docs on Relationship Fields.
I included the many: true option in my example below, because I assumed this is a one-to-many relationship. If it isn't, you can discard it.
var keystone = require('keystone'),
Location = keystone.list('Location');
Location.add({
...
tours: { type: Types.Relationship, ref: 'Tour', many: true },
...
});
The List.relationship() method you mentioned is meant to be used only if you want a list of related documents to automatically appear in the Keystone Admin UI, and not to establish the actual relationship.
Hope this helps.