I am trying to delete a firebase document but the problem is I want to delete specific documents using fields.
as seen above I have user_uid_1 and user_uid_2 in many documents. and I want to match them like every document with (401 and 337) should be deleted when I click delete.
export const deleteChat = (chatId) => {
return async (dispatch) => {
const db = firestore();
db.collection("conversations")
.doc(chatId)
.delete()
.then(() => {
dispatch({
type: userConstants.GET_REALTIME_MESSAGES,
});
})
.catch((error) => {
console.log(error);
});
};
};
You could query using the where method and loop the delete() method for each document found. See sample code below:
const coversations = db.collection('conversations')
.where('user_id_1', '==', '401')
.where('user_id_2', '==', '337');
coversations.get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
doc.ref.delete();
});
});
If (401 and 337) can be in both user_id_1 and user_id_2, you can do a simple logic to check if there's an occurrence on the field. See sample code below:
const coversations = db.collection('conversations');
coversations.get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
const n = ['401', '307'];
if (n.includes(doc.data().user_uid_1) && n.includes(doc.data().user_uid_2)) {
doc.ref.delete();
}
});
});
Related
According to the documentation from firebase you can get a document very simply by using get()
But for some reason in my code it always displays that there's no such document, even though it does exist, this is what I'm doing:
useEffect(() => {
console.log(user, "This is the user UID:"+user.uid)
const userDoc = db.collection('usuarios').doc(user.uid);
const doc = userDoc.get();
if (!doc.exists) {
console.log('No such document!');
}
else {
userDoc
.onSnapshot(snapshot => {
const tempData = [];
snapshot.forEach((doc) => {
const data = doc.data();
tempData.push(data);
});
setUserData(tempData);
})
}
}, [user]);
This is what the console.log() shows:
This is how it looks in firebase:
const doc = userDoc.get();
if (!doc.exists) {
.get returns a promise, so you're checking the .exists property on a promise, which is undefined. You will need to wait for that promise to resolve, either with .then:
userDoc.get().then(doc => {
if (!doc.exists) {
// etc
}
});
Or by putting your code in an async function and awaiting the promise:
const doc = await userDoc.get();
if (!doc.exists) {
// etc
}
If you're using the firebase 8 web version, the userDoc.get() returns a promise, not the document:
userDoc.get().then((doc) => {
if (!doc.exists) {
console.log('No such document!');
} else {
const tempData = [];
const data = doc.data();
tempData.push(data);
setUserData(tempData)
console.log('it worked')
}
}).catch((error) => {
console.log("Error getting document:", error);
});
You can get more info about promises in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises.
In your code you are using the get method to fetch user data and get doesn't provide a snapshot. also, you missed that get() will return a promise so you have to handle using async-await or .then etc.
useEffect(() => {
console.log(user, "This is the user UID:"+user.uid);
getUser(user.uid).then(userData => {
setUserData(userData);
});
}, [user]);
const getUser = async (id) => {
try {
const user = await db.collection('usuarios').doc(id).get();
const userData = user.data();
return userData;
} catch (err){
console.log('Error during get user, No such document!');
return false;
}
I am trying to send a list of arrays to Firestore using a variable called array_list but when I check my firebase console the array is present but the value inside of it is empty.
let array_list = [];
let user_id = localStorage.getItem("userId");
function add_data() {
let i = 0;
for(i;i<10;i++){
array_list.push(i);
}
}
add_data()
let db = firebase.firestore();
if (user_id !== null) {
var doc = db.collection("users").doc(user_id);
}
const sendHistData = () => {
console.log("Creating Database...");
doc
.set({
browsingHistory: array_list,
})
.then(() => {
console.log("Document successfully written!");
})
.catch((error) => {
console.log(error);
});
};
if(user_id!==null){
add_data();
sendHistData();
}
Here is the link to the full code
Here is the screenshot
The var "doc" seems to be undefined in your sendHistData function. Try refactoring the function:
let db = firebase.firestore();
const sendHistData = () => {
// if (!user_id) return null // user not logged in
const db = firebase.firestore().collection("users").doc(user_id)
console.log("Creating Database...");
doc
.set({
browsingHistory: array_list,
})
.then(() => {
console.log("Document successfully written!");
})
.catch((error) => {
console.log(error);
});
};
Also you are checking if user_id is null or not before calling the function so verifying that again inside of the function is redundant.
As described in comments between my code snippet, the asynchronicity is not working as expected. For each id, an object/item should return but it only returns one item since my async await isn't implemented properly. What could be a possible workaround?
Thanks in advance
useEffect(() => {
axios.get('url-here').then((res) => {
res.data.favProperties?.map((el) => {
console.log(el) // this returns multitple id's of saved/liked items
axios.get('url-here').then(async (r) => {
if (r.data) {
console.log(r.data) // Problem starts here
// This returns the full object of the liked items
// But only one object is returned, not every object for which an id was stored
await storageRef
.child(r.data.firebaseRef + '/' + r.data.images[0])
.getDownloadURL()
.then((url) => {
// Here i need to fetch the image for each object
console.log(url)
})
.catch((err) => console.log(err))
}
})
})
})
}, [])
I think breaking down your operations into functions will prevent this Promise Hell. I would recommend using async await for these kinda operations. Also I was confused about the last part of console logging the download URL, by my guess you're trying to save all the download URLs for these liked items in an array.
useEffect(() => {
firstFunction();
}, []);
const firstFunction = async () => {
const { data } = await axios.get("url-here");
const favProperties = data.favProperties;
const fetchedUrls = await Promise.all(
favProperties?.map(async (el) => (
await secondFunction(el.id) /** use el to pass some ID */
))
);
};
const secondFunction = async (someId) => {
/** your second URL must point to some ID (or some parameters) specific API otherwise
running same op in a loop without variations doesn't make any sense */
const { data } = await axios.get(`some-other-url/${someId}`);
if (data) {
console.log(data);
const fetchedUrl = await storageThing(data);
return fetchedUrl;
}
};
const storageThing = async ({ firebaseRef, images }) => {
try {
const downloadURL = await storageRef
.child(firebaseRef + "/" + images[0])
.getDownloadURL();
console.log(downloadURL);
return downloadURL;
} catch (error) {
console.log(error);
return '';
}
};
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));
}
I am making an update to my document. I use the set method because I want to overwrite my fields. Therefore, when i do my set, it works perfectly, modifying the object in the firestore database. But i am not able to return the document afterward. The error I get:
Cannot read property 'exists' of undefined
at Firebase.js:127
Here is my code:
const updateItemFromCollection = async (collectionName, uid, data) => {
return database
.collection(collectionName)
.doc(uid)
.set(data, { merge: true })
.then(doc => {
if (!doc.exists) {
console.log("No such document!"); //Error
} else {
return doc.data();
}
})
.catch(error => {
console.log(error);
});
};
This is because the set() method returns a Promise<void> and not a Promise<DocumentSnapshot<T>>.
You will need to read the document again, as follows:
const updateItemFromCollection = async (collectionName, uid, data) => {
const docRef = database.collection(collectionName).doc(uid);
return docRef.set(data, { merge: true })
.then(() => {
return docRef.get();
.then(doc => {
if (!doc.exists) {
console.log("No such document!"); //Error
} else {
return doc.data();
}
})
.catch(error => {
console.log(error);
});
};
This is the way Firestore works, and AFAIK, it is based on the fact that you already know the value of the document fields, since you passed a corresponding object to set(). One could remark however that this is not true for the values calculated in the back-end based on sentinel values, see FieldValue.