Retrieving object properties from the result fetched from mongodb in nodejs - json

I'm trying to retrieve array of objects properties but I cannot retrieve any properties apart from _id in the object. But I can retrieve the whole array at once or even the individual objects inside array but not the properties that are within each object.
This is the JSON structure
[{
"_id": "5a82df96f2730d4bb177ffe1",
"project_id": 123,
"project_name": "proj11",
"tasks": [],
"links": [],
"__v": 0,
"upsert": true
}]
This the code
taskDelay(req,res) {
ProjectMaster.find({ "project_id": 123 })
.then(response => {
var result = response[0];
var resultId = response[0]._id;
var resultName = response[0].project_name;
var resultProjId = response[0].project_id;
console.log(result); // outputs the object
console.log(resultId); // outputs 5a82df96f2730d4bb177ffe1
console.log(resultName); // undefined
console.log(resultProjId); // undefined
res.status(200).send(response)
})
.catch(error => res
.status(400)
.send(error));
}
What might be the cause for showing undefined for other properties??

Finally, I found the solution for this issue. It is with the data format mongodb sending in response. I tried to do JSON.parse but it didn't work. toObject() did the trick.
taskDelay(req,res) {
ProjectMaster.find({ "project_id": 123 })
.then(response => {
var result = response[0];
var resultId = response[0]._id;
var resultName = response[0].toObject().project_name;
var resultProjId = response[0].toObject().project_id;
console.log(result); // outputs the object
console.log(resultId); // outputs 5a82df96f2730d4bb177ffe1
console.log(resultName); // outputs 123
console.log(resultProjId); // outputs proj11
res.status(200).send(response)
})
.catch(error => res
.status(400)
.send(error));
}
I did a mistake of not reading mongoose document completely! This behaviour is regarding with mongoose data formats.

Related

React map object and embedded object from JSON and convert to single array for state

I have a React component which is performing an axios.get call on JSON file on componentDidMount. The JSON has an object with an embedded object, like so:
This is the initial format:
"objects": {
"5bd4a1a4-f806-4355-bf34-1b4054c2881e": {
"type": "tosca.resourceTypes.TPE",
"label": "BVI 610",
"value": "801070217_BVI610"
},
and this is the console.log after my initial axios.get call.
5bd4a1a0-fd74-4a9f-b7e2-c5ab15360839: {type: "tosca.resourceTypes.TPE", label:
"Bundle-Ether 33", value: "801070217_Bundle-Ether33"}
So I could succesfully get a list of the first item using:
const finalTree = Object.keys(fullTree).map(({item}) => ({id: fullTree[item]}));
but what I need to do is convert finalTree into an array which also contains the type, label and value for each item and then put that into state. I have been messing with jsonQuery but it's not working for me and I'm a relative noobie when it comes to manipulating JSON data. Thanks in advance for any help!
You can use Object.keys to get an array of all the keys, and map that array and create a new object for each key that contains all the fields in its object and the key.
Example
const obj = {
"5bd4a1a4-f806-4355-bf34-1b4054c2881e": {
"type": "tosca.resourceTypes.TPE",
"label": "BVI 610",
"value": "801070217_BVI610"
}
};
const result = Object.keys(obj).map(key => ({
...obj[key],
id: key
}));
console.log(result);
const obj = {
"5bd4a1a4-f806-4355-bf34-1b4054c2881e": {
"type": "tosca.resourceTypes.TPE",
"label": "BVI 610",
"value": "801070217_BVI610"
}
};
const result = Object.keys(obj).map(key => ({
...obj[key],
id: key
}));
console.log(result);

How to access the contents of a JSON file without a key?

Basically, I am setting up a web server via Node.js and Express (I am a beginner at this) to retrieve data by reading a JSON file.
For example, this is my data.json file:
[{
"color": "black",
"category": "hue",
"type": "primary"
},
{
"color": "red",
"category": "hue",
"type": "primary"
}
]
I am trying to retrieve all of the colors by implementing this code for it to display on localhost:
router.get('/colors', function (req, res) {
fs.readFile(__dirname + '/data.json', 'utf8', function (err, data) {
data = JSON.parse(data);
res.json(data); //this displays all of the contents of data.json
})
});
router.get('/colors:name', function (req, res) {
fs.readFile(__dirname + '/data.json', 'utf8', function (err, data) {
data = JSON.parse(data);
for (var i = 0; i < data.length; i++) {
res.json(data[i][1]); //trying to display the values of color
}
})
});
How do I go about doing this?
What you are trying to do is actually pretty simple once you break it into smaller problems. Here is one way to break it down:
Load your JSON data into memory for use by your API.
Define an API route which extracts only the colours from your JSON data and sends them to the client as a JSON.
var data = [];
try {
data = JSON.parse(fs.readFileSync('/path/to/json'));
} catch (e) {
// Handle JSON parse error or file not exists error etc
data = [{
"color": "black",
"category": "hue",
"type": "primary"
},
{
"color": "red",
"category": "hue",
"type": "primary"
}
]
}
router.get('/colors', function (req, res, next) {
var colors = data.map(function (item) {
return item.color
}); // This will look look like: ["black","red"]
res.json(colors); // Send your array as a JSON array to the client calling this API
})
Some improvements in this method:
The file is read only once synchronously when the application is started and the data is cached in memory for future use.
Using Array.prototype.map Docs to extract an array of colors from the object.
Note:
You can structure the array of colors however you like and send it down as a JSON in that structure.
Examples:
var colors = data.map(function(item){return {color:item.color};}); // [{"color":"black"},{"color":"red"}]
var colors = {colors: data.map(function(item){return item.color;})} // { "colors" : ["black" ,"red"] }
Some gotchas in your code:
You are using res.json in a for loop which is incorrect as the response should only be sent once. Ideally, you would build the JS object in the structure you need by iterating over your data and send the completed object once with res.json (which I'm guessing internally JSON.stringifys the object and sends it as a response after setting the correct headers)
Reading files is an expensive operation. If you can afford to read it once and cache that data in memory, it would be efficient (Provided your data is not prohibitively large - in which case using files to store info might be inefficient to begin with)
in express, you can do in this way
router.get('/colors/:name', (req, res) => {
const key = req.params.name
const content = fs.readFileSync(__dirname + '/data.json', 'utf8')
const data = JSON.parse(content)
const values = data.reduce((values, value) => {
values.push(value[key])
return values
}, [])
// values => ['black', 'red']
res.send(values)
});
and then curl http://localhost/colors/color,
you can get ['black', 'red']
What you're looking to do is:
res.json(data[i]['color']);
If you don't really want to use the keys in the json you may want to use the Object.values function.
...
data = JSON.parse(data)
var values = []
for (var i = 0; i < data.length; i++) {
values.push(Object.values(data[i])[0]) // 0 - color, 1 - category, 2 - type
}
res.json(values) // ["black","red"]
...
You should never use fs.readFileSync in production. Any sync function will block the event loop until the execution is complete hence delaying everything afterwords (use with caution if deemed necessary). A few days back I had the worst experience myself and learnt that in a hard way.
In express you can define a route with param or query and use that to map the contents inside fs.readFile callback function.
/**
* get color by name
*
* #param {String} name name of the color
* #return {Array} array of the color data matching param
*/
router.get('/colors/:name', (req, res) => {
const color = req.params.name
const filename = __dirname + '/data.json';
fs.readFile('/etc/passwd', 'utf8', (err, data) => {
if(err){
return res.send([]); // handle any error returned by readFile function here
}
try{
data = JSON.parse(data); // parse the JSON string to array
let filtered = []; // initialise empty array
if(data.length > 0){ // we got an ARRAY of objects, right? make your check here for the array or else any map, filter, reduce, forEach function will break the app
filtered = data.filter((obj) => {
return obj.color === color; // return the object if the condition is true
});
}
return res.send(filtered); // send the response
}
catch(e){
return res.send([]); // handle any error returned from JSON.parse function here
}
});
});
To summarise, use fs.readFile asynchronous function so that the event loop is not clogged up. Inside the callback parse through the content and then return the response. return is really important or else you might end up getting Error: Can't set headers after they are sent
DISCLAIMER This code above is untested but should work. This is just to demonstrate the idea.
I think you can’t access JSON without key. You can use Foreach loop for(var name : object){} check about foreach it may help you

Parse JSON file containing multiple objects

I have a JSON file that contains multiple objects of the same structure that look like this:
{
"id": "123",
"type": "alpha"
}
{
"id": "321",
"type": "beta"
}
I'm using node.js to read the file.
fs.readFile(__dirname + "/filename.json", 'utf8', function(err, data) {
var content = JSON.parse(JSON.stringify(data));
If I do a console.log(content) things look good. I see the content of the json file. I'm trying to iterate over each object but I'm not sure how to do that. I've tried using
for(var doc in content)
but the doc isn't each object as I was expecting. How do I loop over the content to get each object in a json format so that I can parse it?
If content is an array, you can use
content.forEach(function (obj, index) { /* your code */ })
See documentation for Array.prototype.forEach()
if you need to just iterate, a forEach loop would work or a normal for loop :
for(var i = 0; i<content.length(); i++){
//perform whatever you need on the following object
var myobject = content[i];
}
Depend of the files, the two current answer (Osama and Daniel) assume you have a JSON Array:
[
{
"id": "123",
"type": "alpha"
},
{
"id": "456",
"type": "beta"
}
]
In which case, you can use any array iterator:
var async = require('async'),
content = require(__dirname + "/filename.json");
async.each(content, function (item, callback) {
//...
});
But in your case, it seems to not be JSON (no bracket to indicate array, and no comma to separate the objects), so in the case JSON.parse doesn t throw up any error, you'll need to isolate your objects first:
var fs = require('fs'),
async = require('async');
fs.readFile(__dirname + "/filename.notjson", 'utf8', function(err, data) {
var content = data.split('}');
async.map(content, function (item, callback) {
callback(null, JSON.parse(item));
}, function (err, content) {
console.log(content);
};
});

How to convert Backbone fetched object to proper Handlebars JSON Object?

Currently I have an issue with getting back a proper JSON object I'm fetching with Backbone fetch() and putting it into a Handlebars template.
See below my code, I have made a ugly workaround for now to test my Backend API
When converting to JSON with *.toJSON(), it just adds an extra object in-between and I don't need this extra object
Object [0]
--> books
----> Object [0]
------> Array of book
--------> book
--------> cities
JSON
{
"books": [
{
"book": 00001,
"cities": [
"TEST"
]
},
{
"book": 00002,
"cities": [
"TEST"
]
},
{
"book": 00003,
"cities": [
"TEST"
]
}
],
"more": true
}
JavaScript
var Book = Backbone.Model.extend({
default: {
book: 0,
cities: ["TEST1", "TEST2", "TEST3"]
},
url: function () {
return ".list.json";
}
});
var Books = Backbone.Collection.extend({
model: Book,
url: ".list.json"
});
var BooksView = Backbone.View.extend({
initialize: function(){
_.bindAll(this, 'render');
this.collection = new Books();
this.collection.fetch();
this.source = $('.e-books-template').html();
// Use an extern template
this.template = Handlebars.compile(this.source);
var self = this;
this.collection.fetch({
success: function () {
self.render();
},
error: function () {
console.log("ERROR IN BooksView");
}
});
},
render: function() {
var collect = JSON.stringify(this.collection);
collect = collect.slice(1, -1);
var html = this.template($.parseJSON(collect));
this.$el.html(html);
}
});
var booksView = new BooksView({ });
$(document).ready(function(){
booksView.$el = $('.e-books-content');
});
A Backbone collection expects an array of models but your JSON provides an object with the array under a books key. Parse the server response to format the data :
var Books = Backbone.Collection.extend({
model: Book,
url: ".list.json",
parse: function(data) {
return data.books;
}
});
Pass your data to your template via http://backbonejs.org/#Collection-toJSON ,
// directly as an array in your template
var html = this.template(this.collection.toJSON());
// under a books key
var html = this.template({
books: this.collection.toJSON()
});
And a demo http://jsfiddle.net/nikoshr/8jdb13jg/

jqgrid - can I access server response with onSelectRow?

I get a JSON response from the server that I have full access to using loadComplete. Is it possible to be able to access the JSON response using
onSelectRow?
any other custom function defined outside of loadComplete?
You can define a variable which will hold the last state of the JSON response returned from the server:
var serverData;
$('#list').jqGrid({
datatype: 'json',
// ... other parameters
loadComplete: function (data) {
serverData = data; // or serverData = data.rows
// ...
},
onSelectRow: function (id) {
if (serverData) {
// here you can access serverData, but you need
// here probably find the item in the serverData
// which corresponds the id
}
}
});
If you have JSON data for example from the form
{
"total": "xxx",
"page": "yyy",
"records": "zzz",
"rows" : [
{"id" :"1", "cell": ["cell11", "cell12", "cell13"]},
{"id" :"2", "cell": ["cell21", "cell22", "cell23"]},
...
]
}
then you can save in serverData not the data directly. It could be interesting to save only cell part and save it as the value of the serverData[id]:
var serverData = [];
$('#list').jqGrid({
datatype: 'json',
// ... other parameters
loadComplete: function (data) {
var i, rows = data.rows, l = rows.length, item;
for (i = 0; i < l; i++) {
item = rows[i];
serverData[item.id] = item.cell;
}
// ...
},
onSelectRow: function (id) {
var item = serverData[id]; // the part of data which we need
}
});
If you use repeatitems: false setting in the jsonReader then you can save in the serverData only the part of the items (selected properties) which represented the row of the server data.
In any way you should save the part of the information from data parameter of loadComplete in some variable defined outside of the loadComplete.