I would like to be able to delete all of a user's documents when deleting his account. I would like to do this on the backend side with cloud functions.
This similar post doesn't really answer my question (because I need to delete documents from multiple collections)
Here is the structure of my collections:
users
| uid
| email: userEmail#test.com
orders
| docId
| createdBy: uid
| …
| …
Here is my function:
const userDeleted = functions.auth.user().onDelete(user => {
// get user doc in users collection then remove it
const usersRef = db.collection("users").doc(user.uid);
usersRef.delete();
// get all user’s doc in orders collection
const ordersRef = db.collection("orders")
.where("createdBy", "==", user.uid)
.get()
.then(snapshot => {
snapshot.forEach(doc => {
ordersRef.doc(doc.id).delete();
});
})
.catch(err => {
console.log("Error getting documents", err);
});
return Promise.all(usersRef, ordersRef);
})
I need to iterate through the orders collection and find the documents that have the correct uid in the "createdBy" property and then delete them. I feel like I can't delete multiple things at once during onDelete, and I couldn't find anything concrete in the documentation.
Firebase logs return to me this error : object is not iterable (cannot read property Symbol(Symbol.iterator)) at Function.all when deleting a user.
The problem occurs on the following line: return Promise.all(ordersRef);
What am I doing wrong?
Promise.all expects an array of promises, so you need to put [] around the arguments:
return Promise.all([usersRef, ordersRef]);
Related
I'm looking to add the Firestore ID to the DocumentData, so that I can easily utilize the ID when referring to rows in a table, without having to use document.data().property everytime I call a property of a document. Instead, I want to be able to call document.id.... document.property... and so on.
Is there an easy way to do this? Possibly with a Cloud Function that adds the auto-generated ID to the document data?
Thanks!
Example:
export const getSpaces = async () => {
const spaceDocs = await getDocs(spacesCollection)
spaceDocs.docs.forEach((spaceDoc) => {
const spaceID = spaceDoc.id
const spaceData = spaceDoc.data()
console.log(spaceID)
spaces.value.push(spaceData)
})
}
Now, the spaces array has objects containing the data of the documents. But, I loose the ability to reference the ID of a document.
Alternatively, I can add the entire document to the array, but following that, I'll have to access the properties by always including the data() in between. I.e. space.data().name
I'm certain, theres a better way
You don't need Cloud Functions to add the document ID to the data of that document. If you look at the third code snippet in the documentation on adding a document, you can see how to get the ID before writing the document.
In some cases, it can be useful to create a document reference with an auto-generated ID, then use the reference later. For this use case, you can call doc() [without any arguments]:
const newCityRef = db.collection('cities').doc(); // 👈 Generates a reference, but doesn't write yet
// Later...
const res = await newCityRef.set({
newCityRef.id, // 👈 Writes the document ID
// ...
});
As others have commented, you don't need to store the ID in the document. You can also add it to your data when you read the documents, with:
spaceDocs.docs.forEach((spaceDoc) => {
const spaceID = spaceDoc.id
const spaceData = spaceDoc.data()
console.log(spaceID)
spaces.value.push({ id: spaceID, ...spaceData })
})
With this change your spaces contains both the document ID and the data of each document.
A DocumentSnapshot has id property that you are looking for. If you add something within the document, then you'll need to access the data first with doc.data().field_name.
Working on another problem, I came across the solution. Quite simple actually:
When declaring the new Object, you can add ...doc.data() to add all the properties of the DocumentData to the newly created Object, after initialising it with an id. This works for me anyways. Case closed.
onSnapshot(profilesCollectionRef, (querySnapshot) => {
const profilesHolder = [];
querySnapshot.forEach((doc) => {
const profile = {
id: doc.id,
...doc.data(),
}
profilesHolder.push(profile);
console.log(profile);
});
profiles.value = profilesHolder;
});
onSnapshot(doc(db, "profiles", userId), (doc) => {
const newProfile = {
id: doc.id,
...doc.data(),
}
myProfile.value = newProfile as Profile;
});
So here I Have multiple sub-collections(subjects) in different doc's(grades) and I want to get all the sub-collections(subjects) documents(questions) at once I tried to get them by using Collection group queries the only problem which I am facing in my code sometime it returning all the doc's(questions) but sometimes not what is the issue
this is what i have tried
const getAllQuestions = (request,response)=>{
const subjects = ['Maths','English']
const questionsArray = []
subjects.forEach((subject,index)=>{
db.collectionGroup(subject)
.get()
.then((querySnapshot)=>{
querySnapshot.forEach((doc) => {
questionsArray.push({...doc.data(),id:doc.id})
})
if(index==subjects.length-1){
response.status(200).json({
status:200,
data:questionsArray,
length:questionsArray.length
})
}
})
})
}
If you don't want to get the subcollections from all grades, but only from one of them, you should not use a collection group query but instead specify the entire path to the collection you want to query/read:
db.collection('quizQuesDb/Grade 5/'+subject)
.get()
If you want to perform a query across all collections of a certain name under a specific path, see: CollectionGroupQuery but limit search to subcollections under a particular document
I want to build a Firebase Function that checks the "Friends" collection for "scheduled, ==, true" and then create a new document in the "Filings" collection with the "fname".
My Firetore is set up as follows:
Users (collection)
User IDs (documents)
|
|
Friends (collection)
Friends (documents with auto IDs)
[fname, scheduled: true/false]
|
|
Filings (collection)
Filings (documents with auto IDs)
Whenever I run the following function, I get an error stating that the doc is empty, even though it is not. I don't understand why that is. Hoping to get your advice
exports.scheduledFunction = functions.pubsub.schedule('every 5 minutes').onRun(async context => {
const task = await (db.collection('friends').where('scheduled', '==', true).get());
if (task.empty) {
console.log('doc is empty');
return;
}
task.forEach(element => {
console.log(element.id, '==>' , element.data());
});
});
Your friends collection is nested under a users document. Your db.collection('friends') code only accesses the top-level friends collection, which likely doesn't exist.
To access all friends collections, use:
db.collectionGroup('friends').where('scheduled', '==', true).get()
I am having collection with some documents. Each document contains some arrays with strings. I want to know whether given string is there inside the specific document array. I have seen queries to find the documents by using array contains. But I have the document I just want to query whether the string exists inside that document array or not?
var dbRef = dbConnection.db.collection('posts').doc(req.body.post_id);
dbRef.where('likes', 'array-contains', req.body.user_id).get()
.then(data => {
console.log(data);
})
.catch(err => {
console.log(err);
})
I have a document with specific id. I know the document id. That document contains array named as likes. That array will store some strings. I want to know the whether the string exists or not inside that array or not? I am getting the following error
TypeError: dbRef.where is not a function
Then I tried without giving document id. It worked. It returned the documents. But I want to search inside the document array
Your dbRef points to a (single) document, and you can't query a document.
If you want to query the documents in the posts collection, you're looking for:
var dbRef = dbConnection.db.collection('posts');
dbRef.where('likes', 'array-contains', req.body.user_id).get()
...
You can query for both document ID and array contains with:
db.collection('books').where(firebase.firestore.FieldPath.documentId(), '==', 'fK3ddutEpD2qQqRMXNW5').get()
var dbRef = dbConnection.db.collection('posts');
dbRef
.where(firebase.firestore.FieldPath.documentId(), '==', req.body.post_id)
.where('likes', 'array-contains', req.body.user_id).get()
...
Alternatively, you can simply read the document with your original code, and then check client-side whether the array still contains the field:
var dbRef = dbConnection.db.collection('posts').doc(req.body.post_id);
dbRef.get()
.then(doc => {
if (doc.data().likes.indexOf(req.body.user_id) >= 0) {
... the post is liked by the user
}
})
.catch(err => {
console.log(err);
})
I tried to create a user & pet model in Many to Many relationship using mongoDB and sailsJS, db creation and loading the data's are just fine i checked in mongoDB for dbs and collection it exists. when i try to get the user list and pet list its showing me the contents but when i try to GET a single pet by its iD under user by his iD i'm not getting result
It shows "Response does not contain any data."
I tried to get PET like this
"http://localhost:1337/user/54ffd28e9d9ee93c166c7500/pets/54ffd28e9d9ee93c166c7503"
I also tried to display the pet by its name instead of iD its also not working
my sails version is 0.11.0..
my OS is Win7 64 bit
here's a maybe useful thing to know, when requesting by id while using mongoDB.
to get some document inside of a collection, passing the id through an URL, it is useful to use the const { ObjectId } = require('mongodb').
you can for instance do as following:
// VS code might or might not write this for you
// but if you VIM, you have to write yourself
const { ObjectId } = require('mongodb')
fastify.get('/something/:id', async function (req, reply) {
const db = await this.mongo.db;
await db.collection('YourCollection', callbackFunc);
function callbackFunc(err, col) {
if (err) reply.send(err)
col.findOne({ "_id": new ObjectId(req.params.id) }, (err, result) =>
{
console.log(result)
})
}
})
Let me know if it helps, best wishes