React Native : iterate and display nested objects using Hooks - node.js

I want to display my user data stored in my api's
How can I iterate through my apis data.
Can anyone demonstrate it with example ?
My api data looks like this:
{
"data": {
"__v": 0,
"_id": "5edaa8cc76d6b20017",
"createdAt": "2020-06-05T20:19:24.365Z",
"email": "joe#gmail.com",
"name": "Joe",
"role": "user"
},
"success": true
}
Here is the example of my code:
const HomeScreen = props => {
const [dataSource, setDatasource] = useState({});
const Boiler = async () => {
const token = await AsyncStorage.getItem('token');
fetch('{{URL}}/api/v1/auth/me', {
method: 'GET',
headers: new Headers({
Authorization: 'Bearer ' + token,
}),
})
.then(res => res.json())
.then(responeJson => {
console.log(responeJson);
setDatasource({
...dataSource,
dataSource: responeJson,
});
})
.catch(error => {
console.error(error);
});
};
useEffect(() => {
Boiler();
}, []);
}

You response from the API is an object which you can directly render in your component without the need for iteration
Also note that when you update state, you would not explicitly set key as dataSource
Update your state like
setDatasource({
...dataSource,
...responeJson.data,
});
and then render your data like
return (
<View>
<Text>CreatedAt: {dataSource.createdAt}</Text>
<Text>email: {dataSource.email}</Text>
<Text>name: {dataSource.name}</Text>
<Text>role: {dataSource.role}</Text>
</View>
)

If you need to iterate over object use can use for..in loop.
const response = {
"data": {
"__v": 0,
"_id": "5edaa8cc76d6b20017",
"createdAt": "2020-06-05T20:19:24.365Z",
"email": "joe#gmail.com",
"name": "Joe",
"role": "user"
},
"success": true
};
function iterateOverData(data) {
for(let key in data) {
console.log(key, data[key]);
}
}
iterateOverData(response.data);

Related

Firebase database collection returns empty array when trying to get all documents

I'm trying to get all documents from my database collection "posts" but I'm getting an empty array instead.
The strange thing is that I'm able to get all documents from another collection called "users" that has the same structure and using the exact same code.
I've spent days looking for an answer but I haven't been able to find the solution.
This is the request:
const db = admin.firestore();
exports.getAllPosts = (req, res) => {
db.collection('posts')
.orderBy('createdAt', 'desc')
.get()
.then(snapshot => {
let posts = [];
snapshot.forEach((doc) => {
posts.push({
id: doc.id,
body: doc.data().body,
author: doc.data().author,
createdAt: doc.data().timestamp,
voteScore: doc.data().voteScore
});
});
return res.json(posts);
})
.catch(err => {
console.error(err);
res.status(500).json({ error: err.code });
});
}
And this is the response:
[]
This is what my current collection looks like:
Posts collection screenshot
This the response that I get when I return "snapshot":
{
"_query": {
"_firestore": {
"_settings": {
"projectId": "readable-bf7a6",
"firebaseVersion": "9.6.0",
"libName": "gccl",
"libVersion": "4.10.0 fire/9.6.0"
},
"_settingsFrozen": true,
"_serializer": {
"allowUndefined": false
},
"_projectId": "readable-bf7a6",
"registeredListenersCount": 0,
"bulkWritersCount": 0,
"_backoffSettings": {
"initialDelayMs": 100,
"maxDelayMs": 60000,
"backoffFactor": 1.3
},
"_clientPool": {
"concurrentOperationLimit": 100,
"maxIdleClients": 1,
"activeClients": {},
"failedClients": {},
"terminated": false,
"terminateDeferred": {
"promise": {}
}
}
},
"_queryOptions": {
"parentPath": {
"segments": []
},
"collectionId": "posts",
"converter": {},
"allDescendants": false,
"fieldFilters": [],
"fieldOrders": [
{
"field": {
"segments": [
"createdAt"
]
},
"direction": "DESCENDING"
}
],
"kindless": false
},
"_serializer": {
"allowUndefined": false
},
"_allowUndefined": false
},
"_readTime": {
"_seconds": 1622395245,
"_nanoseconds": 513743000
},
"_size": 0,
"_materializedDocs": null,
"_materializedChanges": null
}
Notice how the request for the collection "users" works successfully:
const db = admin.firestore();
exports.getAllUsers = (req, res) => {
db.collection('users')
.orderBy('createdAt', 'desc')
.get()
.then(snapshot => {
let users = [];
snapshot.forEach((doc) => {
let users = [];
snapshot.forEach((doc) => {
users.push({
id: doc.data().userId,
email: doc.data().email,
handle: doc.data().handle
});
});
return res.json(users);
})
.catch(err => {
console.error(err);
res.status(500).json({ error: err.code });
});
}
And the response:
[
{
"id": "EPoHBxhQFUXbcL3TCVx1LdUG2nO2",
"email": "ruben#gmail.com"
},
{
"id": "RqEa3dEq8TSDcZYeolXafju67rB2",
"email": "user10#gmail.com"
},
{
"id": "dxveb4n2iMQej5Q14uprsKRxFp23",
"email": "user4#gmail.com",
"handle": "user4"
},
{
"id": "YQPzBPcsqlVZk9iJEuZTHKUNuVG2",
"email": "user2#gmail.com",
"handle": "user2"
},
{
"id": "CZ05BJxi3TUOpIrmBaz539OWlbC3",
"email": "user#gmail.com",
"handle": "user"
},
{
"id": "t0t83BVwt4gVgJkDv7HL1r1MaKr1",
"email": "userJose2#gmail.com",
"handle": "Jose"
}
]
This is what the users collection looks like in Firebase:
Users collection screenshot
Why is one collection failing when the other works fine and I'm using the same code? What am I missing here?
Thanks in advance and I hope I've made it as clear as possible. Please let me know if you need me to provide anything else.
Very simple my friend, your posts documents can't be ordered like this:
.orderBy('createdAt', 'desc')
Because the post documents does not have the createdAt property, but they have a timestamp property, you should use that property to order your posts like this:
.orderBy('timestamp', 'desc')
I hope that helps 👍
I am not answering directly to #Ruben Garcia Bri, but for future firebase developers who may run into the problem of getting empty documents, I also ran into the same problem, but I solved it by adding a field to the particular document I am trying to retrieve.
Sometimes the cause is because the documents you are trying to get have no field in them.
I mean that a document must have a field before the server can recognize it as an existing document.
So if you run into this problem, consider adding a field to that document before you can successfully retrieve it.

Add key on each json object in Promise

I have the following Promise and Promise.all which works and it returns a json object. However, I want to add a key for each return object.
as of now, it returns something
[value: {school object}, value:{students object}, value:{classroom object}]
desired output:
["schools": {school object }, {students object} , {classroom object} ]
Current Implementation:
new Promise((resolve, reject) => {
const school = getschool (webHost, dataSource, req);
const classRooms = getClassRooms(webHost, dataSource, req);
const students = getstudents (webHost,dataSource, req);
Promise.all([school ,classRooms,students ]).then((res) => {
resolve(res);
})
.catch((error) => {
logger.error(`${error}`);
reject(error);
});
});
classroom
{
"metadata": "metadata",
"value": [
{
"class_id": "171717",
"teacher_name": "Science"
}
]
}
School object
{
"metadata": "metadata",
"value": [
{
"id": "2345354",
"schoolName": "Memorial High School"
}
]
}
Student json
{
"metadata": "metadata",
"value": [
{
"id": "1234",
"studentName": "Beck"
},
{
"id": "5678",
"studentName": "Jeck"
}
]
}
Desired Output:
[
{
"class_id":"171717",
"teacher_name":"Science",
"id":"2345354",
"schoolName":"Memorial High School",
"Students":[
{
"id":"1234",
"studentName":"Beck"
},
{
"id":"5678",
"studentName":"Jeck"
}
]
}
]
It seems like you want to merge the objects to make one unified object of custom type, here is what you want to do:
res => resolve(
{
...res[1].value[0],
...res[0].value[0],
Students: res[2].value
}
)
The ... is called spread syntax. It "explodes" the objects and arrays. What we want here is get the internals of classRooms.value[0] merge them with school.value[0] object's internals, and then, add another attribute at the same level with key as Students which is a not-exploded array specified by student.value.
Here I have created a small TS Playground Example for you to play with the syntax and modify the output the way you may seem fit.
If you run it, it prints the desired output:
{
"class_id": "171717",
"teacher_name": "Science",
"id": "2345354",
"schoolName": "Memorial High School",
"Students": [
{
"id": "1234",
"studentName": "Beck"
},
{
"id": "5678",
"studentName": "Jeck"
}
]
}
-- ORIGINAL ANSWER --
Promise.all returns a promise of resolved objects in an array. So, the .then takes the parameter that's an array of resolved objects in the same order. That means your res parameter is an array of school object, students object, and classroom object in that order. you can do the following to "zip" them up.
new Promise((resolve, reject) => {
const school = getschool (webHost, dataSource, req);
const classRooms = getClassRooms(webHost, dataSource, req);
const students = getstudents (webHost,dataSource, req);
Promise.all([school ,classRooms,students ]).then((res) => {
resolve({"schools": res[0], "classRooms" : res[1], "students": res[2]});
})
.catch((error) => {
logger.error(`${error}`);
reject(error);
});
});
or even better,
.then(([schools, classRooms, students]) => {
resolve({schools, classRooms, students});
})

How to Get the Particular Fields From the response which is in json format

I wanted to extract the repoNames and their Topics from the response body
and the body contains reponames, ids, topics...
which is the github api output
and wanted to extract the fields that are only required from the output body of the api
{
const request = require('request');
// configuration for the url generation
const perPages = 100;
const startPage = 1;
const endPage = 17;
const url = 'https://api.github.com/orgs/organasationName/repos?per_page=%perPages%&page=%page%';
// define a asyncronous call for one url
async function callOneUrl(url) {
// local options for each url
const options = {
'method': 'GET',
'url': url, //To get all the users data from the repos
'headers': {
'Accept': 'application/vnd.github.mercy-preview+json',
'Authorization': 'Bxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
'User-Agent': 'nxxxxxxxxxxxx'
}
}
return new Promise((resolve, reject) => {
request(options, function (error, response) {
if (error) return reject(error);
resolve(response);
});
});
}
// call each url with a for loop
(async () => {
for (let i = startPage; i <= endPage; i++) {
// using the await statement to get the resolved value of the Promise instance or catch the error
try {
var response = await callOneUrl(url.replace('%perPages%', perPages).replace('%page%', i));
// handle response here
console.log(response.body);
} catch (error) {
// handle errors here
throw new Error(error);
}
}
})()
the response body of the api is in json format
the response of the above code is like
{
{ /////output of the above code////
"id": 1 xxxxx '
"name": hvvXxxxx,
"org_id": 1 xxx,
.
.
.
"topics": ["hue", "right", "left"]
}, {
"id": 2 xxxxx '
"name": hvvXxxxxwww,
"org_id": 1 xxx,
.
.
.
"topics": ["hue", "right", "go"]
}, {
"id": 3 xxxxx '
"name": hvvXxxxxttt,
"org_id": 1 xxx,
.
.
.
"topics": ["hue", "right", "left", "good"]
}
}
You could simply use .map to get the required properties like this
const response = [{
"id": "1xxxxx",
"name": "hvvXxxxx",
"org_id": "1xxx",
"topics": ["hue", "right", "left"]
},
{
"id": "2xxxxx",
"name": "hvvXxxxxwww",
"org_id": "1xxx",
"topics": ["sss", "sds"]
}
];
console.log(response.map(i => ({
"org_id": i.org_id,
"topics": i.topics
})));
You can also try lodash lib for that.
Pick loadash
e.g
const response = [{
"id": "1xxxxx",
"name": "hvvXxxxx",
"org_id": "1xxx",
"topics": ["hue", "right", "left"]
},
{
"id": "2xxxxx",
"name": "hvvXxxxxwww",
"org_id": "1xxx",
"topics": ["sss", "sds"]
}
];
const expectedArr = response.map(i => _pick(i, ['name', 'topics', 'etc...']))
Thanks

How can I display a populated document in react

I have a kid document in MongoDB that contains two populated documents: parent and doctor. And I want to display the parent and the doctor information in the details page of the kid.
this is the service in nodeJS:
Router.get('/kids/findKidByID',function (req, res) {
console.log(req.query)
KidModel.findOne({_id: req.params.id}).populate("doctor parent").exec(function (err,u) {
if (err) {
res.send({'state':'not ok','msg':'err:'+err})
console.log('err')
} else {
res.send(u);
console.log('succé')
}
})
});
the kid document:
[{
"firstname": "Salma",
"lastname": "Marzouk",
"doctor": {
"firstname": "Amira",
"lastname": "Messaoudi",
"email": "amira1messaoudi#gmail.com",
},
"parent": {
"firstname": "Radhia",
"lastname": "Hazgui",
}
}]
getone() {
fetch('http://localhost:4000/admin/kids/findKidByID?_id='+ localStorage.getItem("id"), { method: 'GET' } )
.then(response => response.json())
.then(data => {
console.log(data);
this.setState({kid: data})
})
}
but I get an error: Unexpected end of JSON input
Your JSON is not well formatted:
change it to this:
[
{
"firstname":"Salma",
"lastname":"Marzouk",
"doctor":{
"firstname":"Amira",
"lastname":"Messaoudi",
"email":"amira1messaoudi#gmail.com"
},
"parent":{
"firstname":"Radhia",
"lastname":"Hazgui"
}
}
]
and you can use online sites to check your json to see if its valid, sites like this

Using a special API call

I wanted to checkout the GoEuro-Api, but I get:
GoEuroAPI is not a constructor
You can give it a try here:
https://runkit.com/npm/goeuro-api
My code:
var GoEuroAPI = require("goeuro-api");
const GoEuroClient = new GoEuroAPI();
var params = {
"searchOptions": {
"departurePosition": { "id": 376217 },
"arrivalPosition": { "id": 377001 },
"travelModes": ["Flight", "Train", "Bus"],
"departureDate": "2017-04-08",
"returnDate": null,
"passengers": [{ "age": 12 }],
"userInfo": {
"identifier": "0.dj87mh4f039",
"domain": ".com", "locale": "en", "currency": "EUR"
},
"abTestParameters": []
}
};
// Init the search and get flights, trains and buses.
GoEuroClient.search(params)
.then((response) => {
GoEuroClient.flights()
.then(flights => console.log(flights));
GoEuroClient.trains()
.then(trains => console.log(trains));
GoEuroClient.buses()
.then(buses => console.log(buses));
})
.catch((error) => console.log(error));
// Get buses by search_id
GoEuroClient
.buses({ search_id: id })
.then(buses => console.log(buses))
.catch(error => console.log(error));
What is wrong here, what should it be instead ?
Thanks for any help.
while only importing goeuro-api
var GoEuroAPI = require("goeuro-api");
It exposes an object { default: [Function: GoEuroAPI] }
Instead to use the Constructor Function
Do
var GoEuroAPI = require("goeuro-api").default; // exposes a function
// [Function: GoEuroAPI]
const GoEuroClient = new GoEuroAPI();

Resources