Reputation: 93
I'm having difficulty pulling the subcollection when I have queried the document using a .where()
. I keep getting the error:
TypeError: collectionData.where(...).collection is not a function
If I use a standard .doc()
it works, the .where()
does not work.
hotels
is a subcollection of each doc in the main collection. The hotelCollection
is suppose to pass the extracted data through the class to be parsed and executed.
index.js
exports.hotels = functions.https.onRequest((req,res) => {
cors(req, res, () => {
const countryCode = req.url.replace('/', '').toUpperCase();
const hotelCollection = collectionData.where('countryCode', '==', 'VN').collection('hotels');
switch (req.method) {
case 'GET':
Hotels.list(hotelCollection, req, res);
break;
case 'POST':
Hotels.create(hotelCollection, req, res);
break;
default:
res.status(405).send({error: 'An error occurred!'});
break;
}
})
});
hotel.js
let admin = require('firebase-admin');
class Hotels {
static list(hotelCollection, req, res) {
let hotelData = [];
return hotelCollection.collection('hotels').get()
.then(hotels => {
hotels.forEach(hotel => {
hotelData.push(hotel.data());
});
return hotelData;
})
.then(hotelData => {
return res.status(200).send(hotelData);
})
.catch(err => {
return res.status(404).send('Error finding hotel for this country: ' + err);
});
}
static create(hotelCollection, req, res) {
return hotelCollection.add(req.body)
.then(result => {
return res.status(200).send('Hotel has been added!');
})
.catch(err => {
return res.status(404).send('Error adding hotel for this country: ' + err);
});
}
}
module.exports = Hotels;
Upvotes: 0
Views: 131
Reputation: 83093
In your Hotels
class, in the create
method, hotelCollection
shall be a CollectionReference
, since you call the add()
method.
On the other hand, in the list
method, since you do hotelCollection.collection('hotels').get()
, it means that hotelCollection
shall be a DocumentReference
(or hotelCollection
is equal to admin.firestore()
, which does not seem to be the case...).
So, if you want to have the same signature for these two methods, you should pass the CollectionReference
corresponding to the hotels
sub-collection of the document returned by your query.
So, first, adapt the Hotels
class as follows:
class Hotels {
static list(hotelCollection, req, res) {
let hotelData = [];
return hotelCollection.get() // <-- !!! See change here
.then(hotels => {
hotels.forEach(hotel => {
hotelData.push(hotel.data());
});
return res.status(200).send(hotelData); // !!! <-- and also here, we removed a then()
})
.catch(err => {
return res.status(404).send('Error finding hotel for this country: ' + err);
});
}
static create(hotelCollection, req, res) {
return hotelCollection.add(req.body)
.then(result => {
return res.status(200).send('Hotel has been added!');
})
.catch(err => {
return res.status(404).send('Error adding hotel for this country: ' + err);
});
}
}
Then, call it as follows:
exports.hotels = functions.https.onRequest((req,res) => {
cors(req, res, () => {
const countryCode = req.url.replace('/', '').toUpperCase();
const countryQuery = collectionData.where('countryCode', '==', 'VN');
countryQuery.get()
.then(querySnapshot => {
const countryDocRef = querySnapshot.docs[0].ref;
const hotelCollection = countryDocRef.collection('hotels');
switch (req.method) {
case 'GET':
Hotels.list(hotelCollection, req, res);
break;
case 'POST':
Hotels.create(hotelCollection, req, res);
break;
default:
res.status(405).send({error: 'An error occurred!'});
break;
}
});
});
});
You first execute the query, then get the first QueryDocumentSnapshot
of the QuerySnapshot
through the docs
property, then get its DocumentReference
, and finally get the document's hotels
sub-collection, in order to pass it to the Hotels
methods.
Note that above code is based on two assumptions:
countryCode
value, hence the use of docs[0]
;collectionData
variable holds the collection shown on the "Database" screenshot, i.e. the one on the left part of the screenshot.Finally, note that if you want to get the value of the countryCode
from the URL of the GET HTTPS Request (i.e. replace the hardcoded VN
value by a variable value passed through the GET query string parameters), you should use req.query
, see https://flaviocopes.com/express-get-query-variables/
Upvotes: 1