firebase subquery and also head query in next js as getinitialprops - reactjs

I want to have the query with subquery. Lets see the first query:
static async getInitialProps(ctx) {
let product = []
const PostId = ctx.query.pid;
await firebase.firestore()
.collection('products')
.doc(PostId)
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
console.log(doc.id, " => ", doc.data());
});
return product
})
.catch(error => {
console.log('error', error)
})
return {product: product[0]}
}
now I got the information from that query, but I also need subcollections. I found out how to get all subcollection like this, but then I lose the data from above query.
static async getInitialProps(ctx) {
let product = []
const PostId = ctx.query.pid;
await firebase.firestore()
.collection('products')
.doc(PostId)
.collection('offers')
.orderBy('position', 'asc')
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
console.log(doc.id, " => ", doc.data());
});
return product
})
.catch(error => {
console.log('error', error)
})
return {product: product[0]}
}
So is it possible to combine this toghether and get all from collection('products').doc(postID) and all from collection('products').doc(postID).collection('offers') ? So all in one query.

No, it's not possible in one query. Firestore queries are shallow and only consider documents immediately within the collection being queried. There are no SQL-like joins between collections. If you need documents from multiple collections, you will have to perform multiple queries.
The only type of query that can get documents from multiple collections is a collection group query, and those only consider documents among all collections with the same name. You could use that to query all documents among all "offers" subcollections, but you wouldn't be able to filter by anything in a parent document.

Related

Fetch field inside a collection in firestore

I wanted to fetch the fields inside the subcollection but it is returning "undefined" and the database is designed like this:
Collection
Document
Collection
Document
Field
here is the code:
const getEventInfo = async () => {
await firebase
.firestore()
.collection("events/" + eventId + "/agenda")
.doc(customerCollectionIds)
.get()
.then((doc) => {
console.log(doc.data())
})
.catch((error) => {
console.log("Awit Error getting document:", error)
})
}
I am using reactjs. what am I missing here?

How can I display all of these fields?

I can already retrieve the document and it shows in the console but how can I retrieve the individual fields so I can display it in the screen?
useEffect(() => {
const unsubscribe = firestore
.collection("orders")
.where("uid", "==", user.id)
.onSnapshot((snapshot) => {
console.log(snapshot.docs.map((doc) => ({ id: doc.data() })));
});
return () => {
unsubscribe();
};
}, []);
i wanted to get these individual fields and how can I map through the "items"array?
This is what it shows in the console.log and I wanted to access and display the individual fields like the address, items, and delivery date
Document Data as JSON:
[{"id":{"displayName":"Jenn ","items":[{"productPrice":"130","productUserHandler":null,"createdDate":{"seconds":1617787002,"nanoseconds":70000000},"qty":1,"productDesc":"Cheese ","productName":"Pizza","productImg":"https://firebasestorage.googleapis.com/v0/b/ajc-pizza.appspot.com/o/product-images%2Ftunapizza.jpg?alt=media&token=e307d9aa-bc67-4262-94e7-7c7346cc933b","documentID":"MS1PmRyGTWitCaLtV5Xk"},{"documentID":"ndxxdJyS40aRcndJLg9E","productUserHandler":null,"qty":1,"productPrice":"130","productName":"Pizza","productImg":"https://firebasestorage.googleapis.com/v0/b/ajc-pizza.appspot.com/o/product-images%2Fvegetablepizza.jpg?alt=media&token=6f02cd14-6bd9-40dd-9b31-95925578422b","createdDate":{"seconds":1617787021,"nanoseconds":448000000},"productDesc":"Vegetables / Cheese"}],"deliveryDate":"2021-05-08","orderCreatedAt":{"seconds":1619862395,"nanoseconds":463000000},"userID":"kGhSlhM2pIgL9srfXviw9Xew4mI3","total":260,"phone":"+63 9353 276961","address":"US"}},{"id":{"phone":"(555) 555-1234","items":[{"productImg":"https://firebasestorage.googleapis.com/v0/b/ajc-pizza.appspot.com/o/product-images%2Ftunapizza.jpg?alt=media&token=e307d9aa-bc67-4262-94e7-7c7346cc933b","qty":2,"createdDate":{"seconds":1617787002,"nanoseconds":70000000},"documentID":"MS1PmRyGTWitCaLtV5Xk","productName":"Tuna Pizza","productPrice":"130","productUserHandler":null,"productDesc":"Tuna / Cheese "}],"deliveryDate":"2021-05-03","address":"US","displayName":"Jenn ","total":260,"userID":"kGhSlhM2pIgL9srfXviw9Xew4mI3","orderCreatedAt":{"seconds":1619857372,"nanoseconds":32000000}}}]
There's no field named as uid in the document. So please make sure you add it first else the 'where' query won't work as intended. You cannot fetch a single field from Firestore. First fetch the whole document and then use the relevant data.
useEffect(() => {
const unsubscribe = firestore
.collection("orders")
.where("uid", "==", user.id)
.onSnapshot((snapshot) => {
const userOrders = snapshot.docs.map((doc) => ({ [doc.id]: doc.data() }));
console.log(userOrders);
// Logging items of first order
// console.log(userOrders[0]["items"])
});
return () => {
unsubscribe();
};
}, []);
Please use [doc.id]: doc.data() in the map so the keys will be the order IDs (document IDs). When it comes to rendering those on your webpage, you need to use a map function to render all orders first and another map function inside of each to render the items. Let me know if you have further questions.

How to insert array from another query as parameter in DB call FIREBASE

I'm trying to build compound query in Expo react native - firestore.
I have 2 collections in firebase. First "node" is userID and second are IDs of places that had been discovered by this user. Then, I need to take this array of place IDs and pass it as parameter in 2nd query where I got name of each place stored in collection named "databaseOfPlaces". (I want to make scrollable view with names, so maybe I should add listener later on?)
My solution is not working very well. Can you help me? Is this the right way, or is there another way how to save DB call?
Thank you very much.
This is my code:
async componentDidMount() {
db.collection("placesExploredByUsers") // default
.doc("mUJYkbcbK6OPrlNuEPzK") // default
.collection(auth.currentUser.uid)
.get()
.then((snapshot) => {
if (snapshot.empty) {
alert("No matching documents.");
return;
}
const users = [];
snapshot.forEach((doc) => {
const data = doc.data();
users.push(data);
});
this.setState({ users: users });
})
.catch((error) => alert(error));
db.collection("databaseOfPlaces")
.where('placeID','in',this.state.users)
.get()
.then((snapshot) => {
if (snapshot.empty) {
alert("No matching documents.");
return;
}
const places = [];
snapshot.forEach((doc) => {
const data = doc.data();
places.push(data);
});
this.setState({ places: places });
})
.catch((error) => alert(error));
}
Data is loaded from Firestore (and most modern cloud APIs) asynchronously. By the time your second query now runs, the results for the first query are not available yet.
Because of this, any code that needs the results from the first query, will need to be inside the then() callback of that query.
So:
async componentDidMount() {
db.collection("placesExploredByUsers") // default
.doc("mUJYkbcbK6OPrlNuEPzK") // default
.collection(auth.currentUser.uid)
.get()
.then((snapshot) => {
if (snapshot.empty) {
alert("No matching documents.");
return;
}
const users = [];
snapshot.forEach((doc) => {
const data = doc.data();
users.push(data);
});
this.setState({ users: users });
db.collection("databaseOfPlaces")
.where('placeID','in', users)
.get()
.then((snapshot) => {
if (snapshot.empty) {
alert("No matching documents.");
return;
}
const places = [];
snapshot.forEach((doc) => {
const data = doc.data();
places.push(data);
});
this.setState({ places: places });
})
})
.catch((error) => alert(error));
}

Using firestore data in state (React)

How do I go about setting a specific firestore document field to state.When ever i try to run this i get the following warning.
(Im trying to get an array from firestore if that helps)
Possible Unhndled Promis Rejection (id: 0): TypeError: doc.data is not a function. (In 'doc.data()', 'doc.data' is undefined)
class Chart extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
componentDidMount() {
db.collection("users")
.where("email", "==", firebase.auth().currentUser.email)
.get()
.then(doc => {
this.setState({ data: doc.data().prevlevel });
});
}
render(){
const data = this.state.data
.....
You're firing a query against a collection. A query can have multiple results, and thus returns a QuerySnapshot and not a document. Even when there is only one document matching your criteria, it'll still be in a QuerySnapshot.
So your callback will have to iterate over the results. If you only expect one result, you could do that with:
db.collection("users")
.where("email", "==", firebase.auth().currentUser.email)
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
this.setState({ data: doc.data().prevlevel });
})
});
You are currently getting a collection, not a document. If you want to get a doc, you'll need to add that to your request, as in:
db.collection("users")
.where("email", "==", firebase.auth().currentUser.email)
.doc('someId') // <-- Added this, but i don't know exactly what id you need
.then(doc => {
this.setState({ data: doc.data().prevlevel });
});
Or if you do want a collection, then you'll need to use the properties found on collections, as in:
.then(snapshot => {
this.setState({ data: snapshot.docs });
})

Map items of collection snapshot in Firebase Firestore

Firebase Firestore Guides show how to iterate documents in a collection snapshot with forEach:
db.collection("cities").get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log(doc.id, " => ", doc.data());
});
});
I imagined it would support map as well, but it doesn't. How can I map the snapshot?
The answer is:
querySnapshot.docs.map(function(doc) {
# do something
})
The Reference page for Firestore reveals the docs property on the snapshot.
docs non-null Array of non-null firebase.firestore.DocumentSnapshot
An array of all the documents in the QuerySnapshot.
Got pretty sick and tired of Firestore returning stuff in their classes or whatever. Here's a helper that if you give it a db and collection it will return all the records in that collection as a promise that resolves an actual array.
const docsArr = (db, collection) => {
return db
.collection(collection)
.get()
.then(snapshot => snapshot.docs.map(x => x.data()))
}
;(async () => {
const arr = await docsArr(myDb, myCollection)
console.log(arr)
})()
// https://firebase.google.com/docs/firestore/query-data/get-data
const querySnapshot = await db.collection("students").get();
// https://firebase.google.com/docs/reference/js/firebase.firestore.QuerySnapshot?authuser=0#docs
querySnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() }));
Here's another example
var favEventIds = ["abc", "123"];
const modifiedEvents = eventListSnapshot.docs.map(function (doc) {
const eventData = doc.data()
eventData.id = doc.id
eventData.is_favorite = favEventIds.includes(doc.id)
return eventData
})
I have found that a better way to do this by using map and get your document id as well is as follows:
start with the object array I wish to update in your constructor:
this.state = {
allmystuffData: [
{id: null,LO_Name: "name", LO_Birthday: {seconds: 0, nanoseconds: 0},
LO_Gender: "Gender", LO_Avatar: "https://someimage", LO_Type: "xxxxx"},],
};
and in my function do the following
const profile = firebase
.firestore()
.collection("users")
.doc(user.uid)
.collection("stuff")
.get()
.then( async (querySnapshot) => {
console.log("number of stuff records for ",user.uid," record count is: ",
querySnapshot.size);
const profile = await Promise.all(querySnapshot.docs.map( async (doc) => {
const stuffData = doc.data()
stuffData.id = doc.id
condole.log("doc.id => ",doc.id)
return stuffData
}));
this.setState({allmystuffData: profile});
})
.catch(function (error) {
console.log("error getting stuff: ", error);
})
In this example I read all the documents in the collection with querysnapshot the when mapping accross them. the promise.all ensures that all the records are returned before you render it to your screen. I add the document id to the "id" element of each object in the array returned, then I use setstate to replace my state array with the array returned from the query.
you can try this
FirebaseFirestore.instance
.collection('Video_Requests')
.get()
.then((QuerySnapshot querySnapshot){querySnapshot.docs.forEach((doc){
print(doc.data());
});
});

Resources