Loop through array of Mongoose data - javascript

I'm trying to fetch an array of data from Mongoose, loop through the array and add an object to Three.js scene for each item in array.
When I try to render the scene in the browser I'm getting an error saying:
"client_world.js:37 Uncaught (in promise) TypeError: data is not iterable at getData"
However when I console log the data in the get request querying the database, it prints all of the data entries as an array, sp they must be iterable.
I think maybe the data is not arriving to the javascript file.
Here is the code to get the data from the db:
const indexVR = (req, res) => {
Upload.find({})
// .populate('Upload')
.exec(function (err, docs) {
if (err) res.send(err)
// docs.toString()
res.json(docs)
console.log(docs)
})
};
this function is in the following get req:
router.get('/indexvr', FileCtrl.indexVR);
This is the code snippet from the js file:
getData()
async function getData() {
const response = await fetch('/api/indexvr');
const data = await response.json;
console.log(data)
for (item of data) {
try {
scene.add( cube );
} catch (e) {
console.error(e)
}
}
}
nothing in logging to the console in the getData function, however the browser is reading some kind of empty json object.
.. Does anyone know what I'm doing wrong?

Your issue may be as simple as calling the .json method as opposed to referencing it.
Referring to this document: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch .json is a method of the response object returned from fetch.
Try using const data = await response.json();

Related

Error [object object] to JSON: Converting circular structure to JSON [duplicate]

I am using request package for node.js
Code :
var formData = ({first_name:firstname,last_name:lastname,user_name:username, email:email,password:password});
request.post({url:'http://localhost:8081/register', JSON: formData}, function(err, connection, body) {
exports.Register = function(req, res) {
res.header("Access-Control-Allow-Origin", "*");
console.log("Request data " +JSON.stringify(req));
Here I am getting this error :
TypeError: Converting circular structure to JSON
Can anybody tell me what is the problem
JSON doesn't accept circular objects - objects which reference themselves. JSON.stringify() will throw an error if it comes across one of these.
The request (req) object is circular by nature - Node does that.
In this case, because you just need to log it to the console, you can use the console's native stringifying and avoid using JSON:
console.log("Request data:");
console.log(req);
I also ran into this issue. It was because I forgot to await for a promise.
Try using this npm package. This helped me decoding the res structure from my node while using passport-azure-ad for integrating login using Microsoft account
https://www.npmjs.com/package/circular-json
You can stringify your circular structure by doing:
const str = CircularJSON.stringify(obj);
then you can convert it onto JSON using JSON parser
JSON.parse(str)
I was able to get the values using this method, found at careerkarma.com
Output looks like this.
I just run this code in the debugger console. Pass your object to this function.
Copy paste the function also.
const replacerFunc = () => {
const visited = new WeakSet();
return (key, value) => {
if (typeof value === "object" && value !== null) {
if (visited.has(value)) {
return;
}
visited.add(value);
}
return value;
};
};
JSON.stringify(circObj, replacerFunc());
I forgotten to use await keyword in async function.
with the given systax
blogRouter.put('/:id', async (request, response) => {
const updatedBlog = Blog.findByIdAndUpdate(
request.params.id,
request.body,
{ new: true }
);
response.status(201).json(updatedBlog);
});
Blog.findByIdAndUpdate should be used with the await keyword.
use this https://www.npmjs.com/package/json-stringify-safe
var stringify = require('json-stringify-safe');
var circularObj = {};
circularObj.circularRef = circularObj;
circularObj.list = [ circularObj, circularObj ];
console.log(stringify(circularObj, null, 2));
stringify(obj, serializer, indent, decycler)
It's because you don't an async response For example:
app.get(`${api}/users`, async (req, res) => {
const users = await User.find()
res.send(users);
})
This is because JavaScript structures that include circular references can't be serialized with a"plain" JSON.stringify.
https://www.npmjs.com/package/circular-json mentioned by #Dinesh is a good solution. But this npm package has been deprecated.
So use https://www.npmjs.com/package/flatted npm package directly from the creator of CircularJSON.
Simple usage. In your case, code as follows
import package
// ESM
import {parse, stringify} from 'flatted';
// CJS
const {parse, stringify} = require('flatted');
and
console.log("Request data " + stringify(req));
If you are sending reponse , Just use await before response
await res.json({data: req.data});
Came across this issue in my Node Api call when I missed to use await keyword in a async method in front of call returning Promise. I solved it by adding await keyword.
I was also getting the same error, in my case it was just because of not using await with Users.findById() which returns promise, so response.status().send()/response.send() was getting called before promise is settled (fulfilled or rejected)
Code Snippet
app.get(`${ROUTES.USERS}/:id`, async (request, response) => {
const _id = request.params.id;
try {
// was getting error when not used await
const user = await User.findById(_id);
if (!user) {
response.status(HTTP_STATUS_CODES.NOT_FOUND).send('no user found');
} else {
response.send(user);
}
} catch (e) {
response
.status(HTTP_STATUS_CODES.INTERNAL_SERVER_ERROR)
.send('Something went wrong, try again after some time.');
}
});
For mongodb
so if you are getting errors while fetching data from MongoDB then the problem is async
previously
app.get('/users',(req,res,next)=>{
const user=chatUser.find({});
if(!user){
res.status(404).send({message:"there are no users"});
}
if(user){
res.json(user);
}
})
After
app.get('/users',async(req,res,next)=>{
const user=await chatUser.find({});
if(!user){
res.status(404).send({message:"there are no users"});
}
if(user){
res.json(user);
}
})
I came across this issue when not using async/await on a asynchronous function (api call). Hence adding them / using the promise handlers properly cleared the error.
I had a similar issue:-
const SampleFunction = async (resp,action) => {
try{
if(resp?.length > 0) {
let tempPolicy = JSON.parse(JSON.stringify(resp[0]));
do something
}
}catch(error){
console.error("consoleLogs.Utilities.XXX.YYY", error);
throw error;
}
.
.
I put await before JSON.parse(JSON.stringify(resp[0])).
This was required in my case as otherwise object was read only.
Both Object.create(resp[0]) and {...resp[0]} didn't suffice my need.
If an object has a different type of property like mentioned in the above image, JSON.stringify() will through an error.
Try this as well
console.log(JSON.parse(JSON.stringify(req.body)));
TypeError: Converting circular structure to JSON in nodejs:
This error can be seen on Arangodb when using it with Node.js, because storage is missing in your database. If the archive is created under your database, check in the Aurangobi web interface.

Res.send sends an empty object, even though console.log shows it isn't empty?

I am trying to use the google-sheets api with express and don't have much experience with javascript. I'm attempting to use pass a json object from express to react, but it seems that whenever I finally send the object, it just renders as empty on the frontend?
I've tried using res.body/res.data, but the object doesn't seem to have either. I've also tried to put as many awaits as I can everywhere to make sure the object is loaded in before sending, but nothing seems to do the trick. If I use res.json or res.send with just the response object, I get a circular structure converting to JSON error. Here is the code I'm working with.
async function docShit() {
// Initialize the sheet - doc ID is the long id in the sheets URL
const doc = new GoogleSpreadsheet(
"--SPREADSHEET ID--"
);
// Initialize Auth - see https://theoephraim.github.io/node-google-spreadsheet/#/getting-started/authentication
await doc.useServiceAccountAuth({
// env var values are copied from service account credentials generated by google
// see "Authentication" section in docs for more info
client_email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
private_key: process.env.GOOGLE_PRIVATE_KEY,
});
await doc.loadInfo(); // loads document properties and worksheets
const sheet = doc.sheetsByTitle[--WORKSHEET TITLE--];
const rows = await sheet.getRows(); // can pass in { limit, offset }
return rows;
}
app.get("/home", async (req, res) => {
try {
await docShit()
.then((response) => {
res.send(Promise.resolve(response)); //console log shows the object, but res.send just sends nothing??
})
.catch((err) => console.log(err));
} catch (err) {
console.error(err.message);
}
});
There is no res.send at all in your code. Also, you use await and .then together, but I consider them alternatives. Try the following:
app.get("/home", async (req, res, next) => {
try {
var response = await docShit();
console.log(response);
/* If response is circular, decide which parts of it you want to send.
The following is just an example. */
res.json(response.map(function(row) {
return {id: row.id, cells: row.cells.map(function(cell) {
return {id: cell.id, value: cell.value};
};
})};
} catch (err) {
console.error(err.message);
next(err);
}
});

Reading data off JSON file and saving it to database

I am trying to upload a JSON file to my express app, read data from the JSON file and save it as a new document in my MongoDB database.
The documents get saved but the fields don't get added, and that is due to the fields being undefined for some reason, How do I fix this?
When I console.log(obj) i can see the data but when I console.log(obj['DataSource_Name']) for example I get undefined why?
app.post("/upload-config", uploads.single("txt"), async (req, res) => {
// Read the file and send to the callback
fs.readFile(req.file.path, handleFile);
let obj;
// Write the callback function
function handleFile(err, data) {
try {
obj = JSON.parse(data);
console.log(obj["DataSource_Name"]);
} catch (err) {
console.log(err);
}
}
const config = new ConfigM({
DataSource_Name: obj.DataSource_Name,
DataSource_ID: obj.DataSource_ID,
DataSource_Type: obj.DataSource_Type,
DataSource_ICON: obj.DataSource_ICON,
DoubleQuotes_Text: obj.DoubleQuotes_Text,
Delimeter: obj.Delimeter,
Field_list: obj.Field_list,
});
try {
await config.save();
res.send(obj);
} catch (err) {
console.error(err);
}
});
obj is only going to be defined when fs.readFile is ready which is NOT as soon as you called it. That happens asyncronously. So after fs.readFile() is called, the code just continues executing, creating the config object and obj is still not defined.
If you would like to use callback functions as you have here, you probably want your config creation, config.save() and res.send(obj) to be part of the readFile callback. Maybe to try before refactoring you could simply move the closing } right after the } of your final catch.
app.post("/upload-config", uploads.single("txt"), async (req, res) => {
// Read the file and send to the callback
fs.readFile(req.file.path, handleFile);
let obj;
// Write the callback function
function handleFile(err, data) {
try {
obj = JSON.parse(data);
console.log(obj["DataSource_Name"]);
} catch (err) {
console.log(err);
}
const config = new ConfigM({
DataSource_Name: obj.DataSource_Name,
DataSource_ID: obj.DataSource_ID,
DataSource_Type: obj.DataSource_Type,
DataSource_ICON: obj.DataSource_ICON,
DoubleQuotes_Text: obj.DoubleQuotes_Text,
Delimeter: obj.Delimeter,
Field_list: obj.Field_list,
});
try {
await config.save();
res.send(obj);
} catch (err) {
console.error(err);
}
}
});
I am not certain what you precisely are doing by reading the file locally while you got it from the post. Be aware that you will want a lot more security guards all over the place and not accepting path names from the request to decide the path name on your server. But I guess that's all a topic for another stackoverflow question :)

axios.post not returning data from server: "Cannot destructure property 'data' of '(intermediate value)' as it is undefined"

I am trying to get data from server via axios.post().
Decided to use POST and not GET because I want to send an array with ids to look up in the database, which might be too large to fit in GET query params.
I managed to send an array with ids in the body of the POST. This reaches my server. I can successfully find the items in the data base. The items are then returned in the response. The data shows up in Chrome devtools > Network (status 200). I also get the right stuff back when sending a request manually using Postman.
Everything seems to be working fine, but the response does not arrive in my data variable in the axios function.
I spent the day trying out the solutions to all the similar answers here. Nothing worked...
I also tried GET and sending the ids in query params instead, which gives the same error. I suspect I am doing something wrong with async/await because I am getting this "intermediate value" thingy.
Thanks in advance for the help.
CLIENT axios functions
const url = 'http://localhost:5000';
export const getStuff = Ids => {
axios.post(
`${url}/cart/stuff`,
{
Ids: Ids,
},
{
headers: {
'Content-Type': 'application/json',
},
}
);
};
CLIENT actions
import * as api from '../api';
export const getStuff = Ids => async dispatch => {
try {
// Ids is an array like ["5fnjknfdax", "5rknfdalfk"]
const { data } = await api.getStuff(Ids);
// this gives me the error in the title, data never comes through
//dispatch(-dolater-);
} catch (error) {
console.log(error);
}
};
SERVER controllers
export const getStuff = async (req, res) => {
try {
const { Ids } = req.body;
const stuff = await STUFF.find().where('_id').in(Ids);
console.log('SERVER', stuff);
// this works until here. request comes through and
// I can successfully find the stuff I want in the database
res.status(200).json(stuff); // this also works, response is being sent
} catch (error) {
res.status(404).json({ message: error });
}
};
SERVER routes
router.post('/cart/stuff', getStuff);
You have some extra curly braces here (or a missing return, depending on how you look at it). When you use a lambda (arrow function) with curly braces, you have to explicitly return a value or else it will return undefined. Change your code from this:
export const getStuff = Ids => {
axios.post(...);
};
to one of these:
// Option 1
export const getStuff = Ids => {
return axios.post(...);
};
// Option 2
export const getStuff = Ids => axios.post(...);
Either format will return the actual axios promise, instead of the default undefined.
export const fetchPost = () => {
return axios.get(url);
};
This works for me!!

Angular 4.0 http put request

I've written a function to send a http put request to update some data but it says, that it is not recieving any data:
updateHuman(human: Human) {
const url = `${this.url}/${human.id}`;
const data = JSON.stringify(human);
return this.http.put(url, data).map(
response => response.json().data as Human,
error => console.log(error)
);
}
After I've changed my function to the following, it is working:
updateHuman(human: Human) {
const url = `${this.url}/${human.id}`;
const data = JSON.stringify(human);
return this.http.put(url, data).map(() => human);
}
Could someone explain me, why the first function is not working but second is working?
Observables are lazy, you need to be subscribed to them for them to work and retrieve anything. Did you subscribe to your method? Example:
methodToUpdateHuman(human): void{
...
this.updateHuman(human).subscribe((response) => {
//do something with the response
console.log.("Response is: ", response);
},
(error) => {
//catch the error
console.error("An error occurred, ", error);
});
}
I suggest you read through the Angular Tour Of Heroses, it's based in angular 2 and most of the functionality is functional in angular 4, there is a section dedicated to http requests: https://angular.io/tutorial/toh-pt6
In the second example you are not returning the response within the map, you are returning the human that was originally passed in.
So, basically you are creating an illusion that it is working, when it isn't.
Probably best to test your API with something like PostMan, to see if you can get it working with that first.
You use map method incorrectly, read more about this method in documentation: http://xgrommx.github.io/rx-book/content/observable/observable_instance_methods/map.html
If you want receive response from server your code should look like that:
updateHuman(human: Human) {
const url = `${this.url}/${human.id}`;
const data = JSON.stringify(human);
return this.http.put(url, data).subscribe(
response => response.json().data as Human,
error => console.log(error)
);
}
You can use map method if you want to modify server response(map some objects to other structures etc.):
updateHuman(human: Human) {
const url = `${this.url}/${human.id}`;
const data = JSON.stringify(human);
return this.http.put(url, data)
.map(response => { return response.json() }) // you can get json response here
.subscribe(
response => response.data as Human, // -- change here --
error => console.log(error)
);
}
map method returns Observable object, so you can subscribe that and wait for response, error or simple complete method(third parameter of subscribe()):
http://xgrommx.github.io/rx-book/content/observable/observable_instance_methods/subscribe.html

Categories