How can I read JSON data from a Sequelize search? - json

I am developing a handlebars app,
router.get('/findBehavior/:student_id', async (req, res) => {
console.log("---> req.params.student_id :" + JSON.stringify(req.params.student_id));
const student = await Student.findByPk(req.params.student_id,{
include: Behavior,
});
console.log("---> student :" + JSON.stringify(student));
res.render('profile', {student, session: req.session});
});
but I have trouble reading this json data that comes into the profile.handlebars:
{
"student_id": 1,
"student_name": "Martina Hodson",
"student_grade": 9,
"Behaviors": [
{
"behavior_id": 1,
"behavior_name": "No Problems",
"StudentBehavior": {
"student_id": 1,
"behavior_id": 1
}
}
]
}
I am trying this code, but it is not working...
{{student.Behaviors.[0].['behavior_id']}}
I get a response of
[object SequelizeInstance:Behavior]
How can I get the student's name and the student's behaviors?

The problem was not the way I was trying to read the JSON.
It was that the object that comes in response of the search needs to be 'cleaned' before being passed to the handlebars page.
I used this code to make the object plain:
const student = dbStudentData.get({plain: true});
Yo can see how it appears surrounded by the rest of the code:
router.get('/findBehavior/:student_id', async (req, res) => {
console.log("---> req.params.student_id :" + JSON.stringify(req.params.student_id));
const dbStudentData = await Student.findByPk(req.params.student_id, {
include: Behavior,
});
// HERE --------------------------------------------------------
const student = dbStudentData.get({plain: true});
console.log("---> student :" + JSON.stringify(student));
res.render('profile', {student, session: req.session});
});
Since it was only one row of data, It wasn't needed a map function to make plain whole set of data when there is more than one row.

Related

TypeError: Converting circular structure to JSON for mongodb/mongoose

var express = require("express")
let PersonModel = require('./PersonModel')
let mongodbConnected=require('./MongodbConnect')
var app =express()
var bodyparser=require("body-parser")
const { format } = require("path")
const { count } = require("console")
const { countDocuments } = require("./PersonModel")
const { exec } = require("child_process")
const { get } = require("http")
const { ALL } = require("dns")
app.use(bodyparser.urlencoded({extended:false}))
app.get('/',function(req,res){
res.sendFile('Person.html', { root: __dirname });
})
app.get('/about',function (req,res){
res.send("This is a simple express application using mongodb express html and mongoose")
PersonModel.countDocuments().exec()
.then(count=>{
console.log("Total documents Count before addition :", count)
}) .catch(err => {
console.error(err)
})
})
app.post('/add', function(req,res){
Pname=req.body.empname
console.log('Pname',Pname)
PAge=req.body.Age
PGender=req.body.gender
PSalary=req.body.salary
const doc1 = new PersonModel(
{
name:Pname,age:33,Gender:PGender,Salary
:PSalary}
)
doc1.save(function(err,doc){
if (err) return console.error(err)
else
console.log("doc is added ",doc)
//res.send("Record is added"+doc)
res.send({
'status':true,
'Status_Code':200,
'requested at': req.localtime,
'requrl':req.url,
'request Method':req.method,
'RecordAdded':doc});
}
)
})
app.post('/findperson', function(req,res){
PAge=req.body.Age
console.log("Page",PAge)
PersonModel.find({age:{$gte:PAge}})
// find all users
.sort({Salary: 1}) // sort ascending by firstName
.select('name Salary age')// Name and salary only
.limit(10) // limit to 10 items
.exec() // execute the query
.then(docs => {
console.log("Retrieving records ",docs)
res.send(docs)
})
.catch(err => {
console.error(err)})
})
app.post('/delete', function(req,res){
Pgender=req.body.gender
PersonModel.findOneAndDelete({Gender:Pgender }
).exec()
.then(docs=>{
console.log("Deleted")
console.log(docs); // Success
}).catch(function(error){
console.log(error); // Failure
});
})
app.post('/update', function(req,res){
Pname=req.body.empname
Pnewname=req.body.newname
PnewAge=req.body.newage
PersonModel.findOneAndUpdate({ name: Pname },{"$set":{name:Pnewname,age:PnewAge}}).exec()
.then(docs=>{
console.log("Update for what i get is ",Pname
,Pnewname,PnewAge)
console.log(docs); // Success
}).catch(function(error){
console.log(error); // Failure
});
})
var docnum=PersonModel.countDocuments(ALL)
app.post('/count', function(req, res){
res.send('Total number of documents: ', docnum)
})
app.listen(5000,function(){
console.log("Server is running on the port 5000")
})
Hello.
First time posting on stackoverflow, dont know what kind of information to post, please let me know.
Im trying to make a page (/count) to simply display the number of documents. I've tried different code but nothing is working. This error keeps coming up "TypeError: Converting circular structure to JSON".
This is school work so the code is given to me by a teacher and I have to add a POST method to add a page that displays total number of documents.
Any ideas?
Thanks.
Circular structure is not about mongo but how JS read the JSON object.
For example, if you have this object:
var object = {
propA: "propA",
propB: object
}
When JS try to deserialize JSON object, will handle that: One object contains the object that contain again the object and again and again... that is a circular dependence.
Not only with one object itself, aslo with more objects:
var objectA = {
propA: objectB
}
var objectB = {
propA: objectA
}
Is the same case.
Using node.js you can use util.inspecet() which automatically show [Circular] when a circular dependence is found.
You can use like this:
var util = require('util')
console.log(util.inspect(objectA))

Firebase Updating User Data With Custom Fields After Creating User

I want to update the newly created User's data. The returned JSON is:
{
"user":{
"uid":"test123",
"displayName":null,
"photoURL":null,
"email":"test12#test.com",
"emailVerified":false,
"phoneNumber":null,
"isAnonymous":false,
"tenantId":null,
"providerData":[
{
"uid":"test12#test.com",
"displayName":null,
"photoURL":null,
"email":"test12#test.com",
"phoneNumber":null,
"providerId":"password"
}
],
"apiKey":"test123",
"appName":"[DEFAULT]",
"authDomain":"test123.firebaseapp.com",
"stsTokenManager":{
"apiKey":"test123",
"refreshToken":"test123",
"accessToken":"test123",
"expirationTime":1571238989357
},
"redirectEventId":null,
"lastLoginAt":"1571235389108",
"createdAt":"1571235389108"
},
"credential":null,
"additionalUserInfo":{
"providerId":"password",
"isNewUser":true
},
"operationType":"signIn"
}
This is my callout and update:
createUser = async (userData) => {
return await firebase.auth().createUserWithEmailAndPassword(userData.get('userName'), userData.get('password'))
.then((authData) => {
firebase.database().ref('users/' + authData.user.uid + '/').set({
fullName: userData.get('fullName'),
pictures: userData.get('pictures'),
phoneNumber: userData.get('phoneNumber')
});
})
};
Is it possible to add to the User table custom fields?
A few things are happening. It appears that userData can not be seen in the .then statement. So to solve this I attempted to pass in the userData JSON as a param. This did not work. I then broke out each value out of userData, saved it into a const and passed that value. This did not work.
I can see that userData has values in it before the .then statement. I am able to successfully create a new user with the right userName and password. This means to me either:
A - I am not passing the userData JSON correctly or
B - I am not allowed to pass data to firebase like I am doing
My end goal is to sign up a user and then take all of the data they input from a registration form (aka userData) and update the user table with it.
Articles I am using are:
https://firebase.google.com/docs/auth/web/manage-users
https://medium.com/mindorks/firebase-realtime-database-with-react-native-5f357c6ee13b
Main class that calls the createUser function:
const signUp = (dispatch) => {
return async (userData)=>{
try{
const response = await config.createUser(userData);
console.log('sign up resonse1: ' + response); //coming back as undefined
//todo:: figure out how to parse out the apikey out of response
await AsyncStorage.setItem('token', '123mockToken');
dispatch({type: 'sign_up', payload: '123mockToken'});
navigate('mainFlow');
} catch(e){
dispatch({type: 'add_error', payload: '' + e}); //we call dispatch anytime we want to update our state
}
}
};
I understand that the parameter userData holds all the data you want to use for creating the user ("all of the data they input from a registration form").
The following should work:
createUser = async userData => {
try {
const userCredential = await firebase
.auth()
.createUserWithEmailAndPassword(
userData.get('userName'),
userData.get('password')
);
const userId = userCredential.user.uid;
await firebase
.database()
.ref('users/' + userId + '/')
.set({
fullName: userData.get('fullName'),
pictures: userData.get('pictures'),
phoneNumber: userData.get('phoneNumber')
});
return userId; //As per your comment below
} catch (error) {
return error;
}
};
The createUserWithEmailAndPassword() method returns a UserCredential which contains a User.

Data not getting change in node js

I am working with Angular, Node and MySQL. I have a simple crud app in which I am adding,updating some data. Whenever I am adding/updating any data I want it to reflect changes in list grid as well.
I am using popups for add/update. So after adding or updating I am calling my generic function which gives me list of data but I was getting response 304 and changes not displayed in grid. So to overcome 304 I have use app.disable('etag') in Node.js which gives me status 200. But still changes not displayed, but when I refresh page manually I can see the changes.
Also when I am checking data in network just after performing operation it also holds old values.
Node.js
app.post("/addcity", function(req, res) {
d = req.body;
var con = mysql.createConnection(connectionString);
con.connect(function(err) {
if (err)
throw err;
var sql = "INSERT INTO tbl_city(city_name,state_id) VALUES('" + d.city_name + "'," + d.state_id + ")";
console.log(sql);
con.query(sql, function(err, result) {
if (err)
throw err;
res.send(result);
})
})
})
Angular code
PostData(addNewForm: NgForm) {
var object = {
"city_name": addNewForm.value.city_name,
"state_id": addNewForm.value.state_id
}
this.service.addCity(object).subscribe();
this.modalRef.hide();
this.getAllCities(); // this still gives old values even new City is added in database
}
Update
getCities() : Observable<any[]>{
var details = this.http.get(`${this.apiUrl}/cities`);
return forkJoin([details]);
}
You are calling the two requests in async, that's why by the time the city is added in database. this.getAllCities() gets the list of old cities try it like this.
PostData(addNewForm: NgForm) {
var object = {
"city_name": addNewForm.value.city_name,
"state_id": addNewForm.value.state_id
}
this.service.addCity(object).subscribe(
(data)=> {
this.modalRef.hide();
this.getAllCities();
}
);
}

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

Multiple Query Values in Get Request to JSON based Express Api

I have followed this tutorial https://jonathanmh.com/building-a-simple-searchable-api-with-express-backend/. However I can't seem to get it to work even when I copy the source code. I'm not sure if I have done something wrong that I have missed. Basically when using 2 query parameters I get all the records returned in the response. It works with one fine. The api route is
app.get('/api/stores', function(req, res){
var response = [];
console.log(req.query)
// this would usually adjust your database query
if(typeof req.query.nsfw != 'undefined'){
stores.filter(function(store){
if(store.nsfw.toString() == req.query.nsfw){
response.push(store);
}
});
}
// this would usually adjust your database query
if(typeof req.query.location != 'undefined'){
stores.filter(function(store){
if(store.location === req.query.location){
response.push(store);
}
});
}
// de-duplication:
response = _.uniqBy(response, 'id');
// in case no filtering has been applied, respond with all stores
if(Object.keys(req.query).length === 0){
response = stores;
}
res.json(response);
});
The JSON file is
const stores = [
{
id: 1,
name: 'Hollows End Grim Potions',
imageURL: 'https://images.unsplash.com/photo-1465433360938-e02f97448763? auto=format&fit=crop&w=1267&q=60&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D',
location: 'Hollows End',
nsfw: true
},
{
id: 2,
name: 'Lembas Food Truck',
imageURL: 'https://images.unsplash.com/reserve/DHHQbqc0RrWVf0uDNe5E_The%20Litte%20Cafe.jpg?auto=format&fit=crop&w=1489&q=60&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D',
location: 'Lothlorien',
nsfw: false
},
{
id: 3,
name: 'Galadriels Mirror of Brutal Truth',
imageURL: 'https://images.unsplash.com/photo-1497519098947-a305f214d3bc?auto=format&fit=crop&w=1350&q=60&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D',
location: 'Lothlorien',
nsfw: true
},
{
id: 4,
name: 'Jabbas Light Sabers',
imageURL: 'https://images.unsplash.com/photo-1481241857164-e8483bce922d?auto=format&fit=crop&w=1353&q=60&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D',
location: 'Mos Eisley',
nsfw: true
}
];
module.exports = stores;
So to reiterate my question- why if I place http://localhost:3000/api/stores?location=Lothlorien&nsfw=true do I not only get id:3? Right now I get all records returned.
EDIT:
I just tried it with http://localhost:3000/api/stores?location=Lothlorien&nsfw=false and I strangely get two records ID:2 & ID:3 when I should only be getting ID:2
You're filtering on the conditions separately and pushing the results of each onto your response array instead of using && to filter both conditions together.
For example when filtering on location=Lothlorien OR nsfw=true, you get 2 results for the location and 3 for the nsfw which uniquely includes 4 (all of them). However, if it had to meet both criteria together, you'd expect to get 1 result - only 1 location named Lothlorien that has nsfw of false.
Here's an example using &&:
const { location=null, nsfw=null } = req.query;
if (location && nsfw) {
stores.filter((store) => {
if(store.nsfw.toString() === nsfw && store.location === location){
response.push(store);
}
});
}
I got here via the link to this page in the comment of the article. I too was wanting the server code to behave differently, so I fiddled around with this a bit and got the results I was looking for. I hope this answers the Original Posters' question. Here is my entire server.js file:
const express = require('express');
const app = express();
const stores = require('./data/stores');
// npm i express-query-boolean
const boolParser = require('express-query-boolean');
app.use(boolParser());
app.get('/', function (req, res) {
res.send('Hello World!')
});
app.get('/api/stores', function (req, res) {
let response = [];
const q = req.query; // Query object
if (Object.keys(q).length === 0) {
// NO query parameters, send it all...
response = stores;
} else {
// We have a query, filter response to match request
response = stores.filter(function (store) {
return Object.keys(this).every((key) => store[key] === this[key]);
}, q);
}
res.json(response);
});
app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});