Get firestore data as array - javascript

Im tryng to display firestore data but I just get one value. I have try forEach and map. Nothing is working. Heres my code:
React.useEffect(() => {
retrieveNetwork();
}, []);
const retrieveNetwork = async () => {
try {
const q = query(collection(db, "cities", uidx, "adress"));
const querySnapshot = await getDocs(q);
let result = [];
//querySnapshot.docs.map((doc) => setGas(doc.data().home));
querySnapshot.docs.map((doc) => {
result.push(doc.data().home);
setGas(result);
});
} catch (e) {
alert(e);
}
};```

The .map method returns an array (official docs here), so you could do something like this:
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
React.useEffect(() => {
retrieveNetwork();
}, []);
const retrieveNetwork = async () => {
try {
const q = query(collection(db, "cities", uidx, "adress"));
const querySnapshot = await getDocs(q);
// an array from the docs filled only with "home" data
const results = querySnapshot.docs.map((doc) => {
return doc.data().home;
});
// only update the state once per invokation
setGas(results)
} catch (e) {
alert(e);
}
};

Related

Read array from Firebase Document

I have an array of URLS stored within a document that i'd like to read and display as individual cards. All I'm getting is the return of the whole array, I'm not mapping it correctly and I don't know where I'm going wrong.
Currently, it's displaying "https://website1.com, https://website2.com". Where as I would like it to be individual items.
const getInternalLinks = async () => {
try {
const query = await db
.collection("internallinks")
.get()
.then((snapshot) => {
const tempData = [];
snapshot.forEach((doc) => {
const data = doc.data();
tempData.push(data);
});
setInternalLinks(tempData);
});
} catch (err) {
console.error(err);
};
};
useEffect(() => {
getInternalLinks()
},[])
return (
{internalLinks.map((doc, index) => {
<Card>
<p>{doc.urls.urls}</p>
</Card>
}))
);
Firebase Collection Structure
Try adding it directly to the state:
const [internalLinks, setInternalLinks] = useState([]);
const getInternalLinks = async () => {
try {
const query = await db
.collection("internallinks")
.get()
.then((snapshot) => {
snapshot.forEach((doc) => {
const data = doc.data();
setInternalLinks([ ...internalLinks, data ]);
});
});
} catch (err) {
console.error(err);
};
};

How to get specific data from all documents from a collection in firebase?

Platform: React Native (Expo)
So I'm trying to get two values (dotCoins and name) from my firebase db and I can't figure out how to go about it. Here's my firebase structure:
This is what I currently have in place:
// Calling function when screen loads
componentDidMount() {
this.getDotCoins();
this.getUserData();
}
// Calling function when it updates
componentDidUpdate() {
this.getDotCoins();
this.getUserData();
}
// The function
getUserData = async () => {
const querySnapshot = await getDocs(collection(db, "users"));
const tempDoc = [];
querySnapshot.forEach((doc) => {
console.log(doc.id, " => ", doc.data());
});
console.log(tempDoc);
};
Both the console.log() prints nothing, and my console remains absolutely empty. I can't find where I'm going wrong since I don't receive any errors too. (I have all packages installed correctly and all functions imported too)
You are not pushing any document data to tempDoc so it'll always be empty. Try refactoring the code as shown below:
getUserData = async () => {
const querySnapshot = await getDocs(collection(db, "users"));
const tempDoc = querySnapshot.docs.map((d) => ({
id: d.id,
...d.data()
}));
console.log(tempDoc);
};
const q = query(collection(db, "users"));
const unsubscribe = onSnapshot(q, (querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(doc.data())
})
});
});
return unsubscribe;

How do I convert the firestore data to a JSON object?

I have these codes:
const App = () => {
const [users, setUsers] = useState();
const getData = async () => {
const citiesRef = firestore.collection("users");
const snapshot = await citiesRef
.where("item.itemName", "==", true)
.where("item", "==", false)
.get();
if (snapshot.empty) {
console.log("No matching documents.");
return;
}
snapshot.forEach((doc) => {
console.log(doc.data());
});
};
useEffect(() => {
getData();
});
return <div>Month</div>;
};
export default App;
If I'll console.log(doc.data()) this is what is shows:
How can I convert this into a JSON object?
I wanted to have a JSON object in order to filter the data. Thank you.
If you are trying to get an array of objects containing all documents' data to filter them, try this:
const usersData = snapshot.docs.map(d => ({id: d.id, ...d.data()}))
// set this array in your state
setUsers(usersData)
This will be an array and you can use methods like filter(), find() as required. For example, to get users having admin role in their roles array:
const admins = usersData.filter(user => user.roles.includes("admin"))

convert multiple objects into an array of objects

I have created a function where i have passed an object as an argument and there are multiple objects which is passed on one by one and the output is an object but it comes as an individual object which is fine because I have written the code in that way now i wanted to store the objects into an array so it becomes an array of objects.and store for all objects
here is the tried code which gives single object example
const {db} = require('./constant')
const momentTz = require("moment-timezone");
const { getAuth } = require("./constant");
const officeStatus = async officeActivity => {
let output = {};
const maileventQuerySnapshot = await db
.collection("MailEvents")
.where("office", "==", officeActivity.office)
.where("event", "==", "delivered")
.limit(1).get();
output["office"] = officeActivity.office;
output["First Contact"] = officeActivity.attachment["First Contact"].value;
output["Second Contact"] = officeActivity.attachment["Second Contact"].value;
output["Office Creation Date"] = momentTz
.tz(officeActivity.timestamp, officeActivity.attachment.Timezone.value)
.format("DD MMM YYYY");
output["Reports Sent"] = maileventQuerySnapshot.docs.length ? true:false
const officeSubcollectionSnapshot = await db
.collection(`Offices/${officeActivity.officeId}/Addendum`)
.where("date","==",parseInt( momentTz(new Date()).subtract(1, "days").format("DD")))
.where('month', '==', parseInt( momentTz(new Date()).subtract(1, 'days').format("MM"))-1)
.where('year', '==',parseInt( momentTz(new Date()).subtract(1, "days").format("YYYY")))
.orderBy("user").orderBy('timestamp')
.get();
output['Number of unique Checkin Yesterday'] =
officeSubcollectionSnapshot.docs.length;
const activitiesRefSnapshot = await db
.collection("Activities")
.where("office", "==", officeActivity.office)
.where("template", "==", "subscription")
.where("attachment.Template.value", "==", "check-in")
.get();
const phoneNumberArray = [];
activitiesRefSnapshot.forEach(doc => {
phoneNumberArray.push(doc.data().attachment["Phone Number"].value);
});
const userRecord = await Promise.all(phoneNumberArray.map(getAuth));
output["Number of checkin Subscription Auth"] = userRecord.filter(
doc => doc !== undefined
).length;
output["Number of Checkin Subscription No Auth"] = userRecord.filter(
doc => doc === undefined
).length;
return { output};
};
module.exports = { officeStatus };
and the other file where i have queried the office and passed objects as an argument
const {admin,db} = require('./constant');
const { officeStatus } = require("./officeStatus");
let execute = async () => {
try {
let office = await db.collection("Offices").where("status", "==", "PENDING").get();
office.forEach(doc => {
officeStatus(doc.data())
.then(e => {
console.log(JSON.stringify(e.output));
})
.catch(error => {
console.log(error);
});
});
return;
} catch (error) {
console.log(error);
}
return;
};
execute();
admin.apps[0].delete();
I have get output in this way
{}
{}
{}....
and I wanted the output in this way
[{},{},{}]
The promise inside forEach is not correct. It wouldn't give you expected results. You shouldn't use that as it is not supported. You should consider using for..of or Promise.all. In your case I would suggest to use Promise.all as you need result in array.
Promise.all(office.docs.map(doc => {
return officeStatus(doc.data())
.then(e => {
return e.output;
})
.catch(error => {
console.log(error);
});
}))
.then(res => console.log(res));
Try doing that :
// and the other file where i have queried the office and passed objects as an argument
const {admin,db} = require('./constant');
const { officeStatus } = require("./officeStatus");
let execute = async () => {
try {
let office = await db.collection("Offices").where("status", "==", "PENDING").get();
let arr = new Array();
office.forEach(doc => {
officeStatus(doc.data())
.then(e => {
arr.push(e)
})
.catch(error => {
console.log(error);
});
});
console.log(arr)
return;
} catch (error) {
console.log(error);
}
return;
};
execute();
admin.apps[0].delete();
I just created an array where we push e when we did officeStatus. Then, at the end of the code, we log arr ; the declared array.
const {admin,db} = require('./constant');
const { officeStatus } = require("./officeStatus");
let execute = async () => {
let office = await db.collection("Offices").where("status", "==", "PENDING").get()
const arrayofObject = await Promise.all(office.docs.map(doc => {
return officeStatus(doc.data())
.then(e => {
// console.log(JSON.stringify(e.output));
return e.output;
})
.catch(error => {
console.log(error);
});
}))
console.log(arrayofObject)
return;
};
execute();
admin.apps[0].delete();

How to fetch data from multiple urls at once?

I have a function that fetches from a url in React
const DataContextProvider = (props) => {
const [isLoading, setLoading] = useState(false);
const [cocktails, setCocktails] = useState([]);
useEffect(() => {
const fetchCocktailList = async () => {
const baseUrl = 'https://www.thecocktaildb.com/api/json/v1/1/';
setLoading(true);
try {
const res = await fetch(`${baseUrl}search.php?s=margarita`);
const data = await res.json();
console.log(data);
setCocktails(data.drinks);
setLoading(false);
} catch (err) {
console.log('Error fetching data');
setLoading(false);
}
};
fetchCocktailList();
}, []);
How I'm mapping data so far.
const DrinkList = () => {
const { cocktails } = useContext(DataContext);
return (
<div className='drink-list-wrapper'>
{cocktails.length > 0 &&
cocktails.map((drink) => {
return <DrinkItem drink={drink} key={drink.idDrink} />;
})}
</div>
);
};
However I want to fetch from this url also ${baseUrl}search.php?s=martini
I would like a good clean way to do this and set my state to both of the returned data.
First base the data fetch function on a parameter:
const fetchCocktail = async (name) => {
const baseUrl = 'https://www.thecocktaildb.com/api/json/v1/1/';
try {
const res = await fetch(`${baseUrl}search.php?s=` + name);
const data = await res.json();
return data.drinks;
} catch (err) {
console.log('Error fetching data');
}
}
Then use Promise.all to await all results:
setLoading(true);
var promises = [
fetchCocktail(`margarita`),
fetchCocktail(`martini`)
];
var results = await Promise.all(promises);
setLoading(false);
DrinkList(results);
Where results will be an array with the responses that you can use on the DrinkList function.
Here's a method which will let you specify the cocktail names as dependencies to the useEffect so you can store them in your state and fetch new drink lists if you want new recipes. If not, it'll just be a static state variable.
I've also added another state variable errorMessage which you use to pass an error message in the case of failure.
Also, you should include the appropriate dependencies in your useEffect hook. The setState functions returned by calls to useState are stable and won't trigger a re-run of the effect, and the cocktailNames variable won't trigger a re-run unless you update it with new things to fetch.
const DataContextProvider = (props) => {
const [isLoading, setLoading] = useState(false);
const [cocktails, setCocktails] = useState([]);
const [errorMessage, setErrorMessage] = useState(''); // holds an error message in case the network request dosn't succeed
const [cocktailNames, setCocktailNames] = useState(['margarita', 'martini']); // the search queries for the `s` parameter at your API endpoint
useEffect(() => {
const fetchCocktailLists = async (...cocktailNames) => {
const fetchCocktailList = async (cocktailName) => {
const baseUrl = 'https://www.thecocktaildb.com/api/json/v1/1/search.php';
const url = new URL(baseUrl);
const params = new URLSearchParams({s: cocktailName});
url.search = params.toString(); // -> '?s=cocktailName'
const res = await fetch(url.href); // -> 'https://www.thecocktaildb.com/api/json/v1/1/search.php?s=cocktailName'
const data = await res.json();
const {drinks: drinkList} = data; // destructured form of: const drinkList = data.drinks;
return drinkList;
};
setLoading(true);
try {
const promises = [];
for (const cocktailName of cocktailNames) {
promises.push(fetchCocktailList(cocktailName));
}
const drinkLists = await Promise.all(promises); // -> [[drink1, drink2], [drink3, drink4]]
const allDrinks = drinkLists.flat(1); // -> [drink1, drink2, drink3, drink4]
setCocktails(allDrinks);
}
catch (err) {
setErrorMessage(err.message /* or whatever custom message you want */);
}
setLoading(false);
};
fetchCocktailList(...cocktailNames);
}, [cocktailNames, setCocktails, setErrorMessage, setLoading]);
};
var promises = [
fetchCocktail(api1),
fetchCocktail(api2)
];
var results = await Promise.allSettled(promises);

Categories