Firebase React: Remove Item (Map) from array in firestore - javascript

I'm trying to remove a map item from an array in firebase. From what I understand with firebase - you are unable to delete the item based on the index. Should I structure this a different way or is there an easier way to remove a specific object from the array? Thank you
Error: 'No document to update: '
const listingRef = doc(db, 'users', 'savedListings');
const deleteListing = async () => {
try {
await updateDoc(listingRef, {
savedListings: deleteField()
});
} catch (e) {
console.log(e.message);
}
};```

The doc() takes path to a document that should be users/test#user.com in this case. While you can use arrayRemove() to remove elements from an array field you cannot delete an object from an array unless you know the exact value that object including all the fields.
const listingRef = doc(db, 'users', 'USER_EMAIL'); // USER_EMAIL is document ID
const deleteListing = async () => {
try {
await updateDoc(listingRef, {
savedListings: arrayRemove("THAT_OBJECT")
});
} catch (e) {
console.log(e.message);
}
};
If you don't have that exact object, then you'll have to read the document, manually remove the element from array and update the document back.

Related

deleteDoc() gets TypeError and not deleting document from firestore db in my react app

I am new to firebase and quite new to react, I'm developing a shopping list app. I add documents to my db using setDoc() like that:
const addToFirestore = async () => {
if (tilesToDB.indexOf(tile) === -1) {
setTilesToDB((prev) => [...prev, tile]);
await setDoc(doc(db, 'list', tile.contents), tile);
}
}
The item is added either by clicking on the add button or by clicking outside input field after typing item's name.
When i try to delete document in similar fashion, by deleteDoc():
const removeFromFirestore = async (id) => {
const docRef = (db, 'list', id);
await deleteDoc(docRef).then(() => {
console.log("Entire Document has been deleted successfully.")
})
.catch(error => {
console.log(error);
});
}
and then calling the above function by clicking remove button:
onClick={(e) => {
e.preventDefault();
console.log(tile.id, 'tile to remove');
setItems(items.filter((el, i) => i !== items.indexOf(tile)));
removeFromFirestore(tile.contents);
console.log('test', items);
}
i get Uncaught (in promise) TypeError: Cannot use 'in' operator to search for '_delegate' in undefined
The rest of the code works fine, including the setItems() call in above function, which deletes item in the browser, but it's not subsequently deleted from db. the console.log call shows that the right document id is being passed to deleteDoc(). I also made sure to have all the relevant imports.
You are mixing async/await and .then()/.catch(). You do NOT want to do this. You will not be happy with the results.
Simply change your code to:
const removeFromFirestore = async (id) => {
const docRef = (db, 'list', id);
try {
await deleteDoc(docRef)
console.log("Entire Document has been deleted successfully.");
} catch(ex) {
console.log(ex);
}
}
Later in your code you call: removeFromFirestore(tile.contents); Is tile.contents a valid id value, which is what removeFromFirestore() is expecting?
You might consider doing a console.log('docRef path is', docRef.path) inside removeFromFirestore() right after giving docRef a value, just to be sure that it is the path you expect it to be.

Trouble batch setting a document field by docId in Firestore

I have been using firebase (firestore) for a while but I'm a little stuck and was wondering if anyone can think of a solution.
On the firestore DB I have a single collection of users, each user has an email address and several other fields. In this instance I am checking if a user email exists and if it does, I want to create a list field for that particular user with a listUid. I am referencing the users by email, grabbing the docId for those users and then trying to set a list field for each of them.
I am not getting any error's from firestore, it's simply not updating in the DB for some reason and I can't figure out where I am going wrong. Thanks in advance
export const addListUidToExistingUserList = (
{ firestore },
emailArray,
listUid
) => {
return async () => {
let docIds = [];
emailArray.forEach((emailAddress) => {
//find users by email (works)
const query = db
.collection("users")
.where("email", "==", emailAddress);
//get docId's for user with matching email (works)
query.get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
docIds.push(doc.id);
});
});
//add a new list with corresponding listUid (does not work)
docIds.forEach((id) => {
let userRef = db.collection("users").doc(id);
batch.set(userRef, { lists: [{ listUid }] });
});
});
return await batch.commit();
};
};
You are running into this issue because your docIds array is always empty at the time you call docIds.forEach.
That's because query.get().then runs asynchronously, and so docIds.forEach is not waiting for it to complete.
You could either:
await query.get().then; or
Add the docIds.forEach function INSIDE the then callback of query.get.
Here are your possible fixes:
await query.get().then
//get docId's for user with matching email (works)
await query.get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
docIds.push(doc.id);
});
});
OR:
docIds.forEach inside then
//get docId's for user with matching email (works)
query.get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
docIds.push(doc.id);
});
docIds.forEach((id) => {
let userRef = db.collection("users").doc(id);
batch.set(userRef, { lists: [{ listUid }] });
});
});
Note: Of course, you could also add batch.set directly into your first iteration of querySnapshot.docs.forEach to prevent an unnecessary iteration.

Google Cloud Function to delete sub-collections on "missing documents

I have a Firestore collection called Posts, and each document in Posts could have a sub-collection called Post-Likes and/or Post-Comments. When I delete the Posts document, it does not delete the sub-collection so I am left with a reference to a missing document in Firestore which looks like this:
I am using the following code in my Google Cloud Function to find references in the Post collection with missing data, then for each document with a missing reference, I want to delete the sub-collections Post-Likes and Post-Comments. For now, I am just try to list the sub-collection document so I can delete them, but I am getting an error.
function deleteOrphanPostSubCollections() {
let collectionRef = db.collection('Posts');
return collectionRef.listDocuments().then(documentRefs => {
return db.getAll(...documentRefs);
}).then(documentSnapshots => {
for (let documentSnapshot of documentSnapshots) {
if (documentSnapshot.exists) {
console.log(`Found document with data: ${documentSnapshot.id}`);
} else {
console.log(`Found missing document: ${documentSnapshot.id}`);
return documentSnapshot.getCollections().then(collections => {
return collections.forEach(collection => {
console.log('Found subcollection with id:', collection.id);
});
});
}
}
return
});
}
However, I am getting the following error. Please help me resolve this issue.
This is because there is not getCollections() method for a DocumentSnapshot.
If you want to list all the collections of the Document corresponding to the DocumentSnapshot, you need to use the listCollections() method, as follows:
documentSnapshot.ref.listCollections()
.then(collections => {
for (let collection of collections) {
console.log(`Found subcollection with id: ${collection.id}`);
}
});
In addition, note that if you call an asynchronous method in a loop, it is recommended to use Promise.all() in order to return a single Promise that resolves when all the "input" Promises are resolved.

Trying to save an array of objects to Firestore and load it back

How do I save an array of objects to Firestore and load it back? I get this error
Uncaught FirebaseError: Function DocumentReference.set() called with
invalid data. Unsupported field value: a custom object (found in
document userBooks/library)
This is my code to save it to Firebase and to load it later on after modifications have been done to myLibrary array.
let myLibrary = [];
let firestore = firebase.firestore();
let docRef = firestore.doc("userBooks/library");
saveLibrary = function () {
docRef
.set({
userLibrary: myLibrary,
})
.then(function () {
console.log("Library saved!");
})
.catch(function (error) {
console.log("Got an error: ", error);
});
};
saveLibrary()
getUpdate = function () {
docRef.onSnapshot(function (doc) {
if (doc && doc.exists) {
const myData = doc.data();
myLibrary = myData.userLibrary;
console.log(myData.userLibrary);
}
});
};
// Here I add multiple objects to the array myLibrary.
saveLibrary();
getUpdate();
It looks like you're trying to store an empty array inside the document, then start to listen to updates?
I wouldn't store the empty array until it has data inside it, or store it with boilerplate data.
In your code, you're calling " saveLibrary() " before adding objects to it. I think that's what's causing the issue.
I would also encourage you to use {merge:true} within your .set() functions, so you don't overwrite your documents. ref here

How to get the unique id (key) of a document in Firebase database collection?

I am trying to fetch the documents of a collection in my React-Native app but I dont know how to fetch them by ID (key).
P.S: I dont have any field called unique id or id inside the document but as I have understood, the unique id is the auto-generated key when I create a document which stands as the name of that document (20 characters id).
This is how I fetch all the fields inside a document:
var ref = firebase.firestore().collection('discounts')
.orderBy('rest_id')
EDIT:
getDiscounts = () => {
try {
this.setState({
loading: true
})
var ref = firebase.firestore().collection('discounts')
.orderBy('rest_id')
.limit(this.state.limit)
ref.onSnapshot((querySnapshot => {
var discounts = querySnapshot.docs.map(document => document.data());
var lastVisibleDiscount = discounts[discounts.length - 1].rest_id;
this.setState({
discounts: discounts,
lastVisibleDiscount: lastVisibleDiscount,
loading: false,
});
}));
}
catch (error) {
console.log(error);
}
}
To print the keys of the documents in the collection in the order of the value of their rest_id field, you can do something like this:
firebase.firestore().collection("discounts").orderBy('rest_id').get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log(doc.id);
});
});
This is an almost literal copy of the code in the documentation on getting all documents from a collection, so I recommend spending some time there.
You can use (using await/async)
const ref = await ref.get()
It will have an array called docs that you can map over to get the id and data of the document:
const data = ref.docs.map(doc => {return {id: doc.id, data: doc.data()} })

Categories

Resources