How to get a Firestore document ID based on its content? - javascript

I am trying to get a way to delete firestore document by a click event.
here is what i have so far. x is the document id i get from firestore. But how to get the ID change dynamically based on the content show in the page? SO that user can delete the content they wanted.
var deleteContent = document.getElementById('delete');
deleteContent.addEventListener('click', function(e) {
// get current document ID
x = 'poOjcQce2iiKzp2FaFVA'
var getId = db.collection("checkin").doc(x);
getId.delete().then(function() {
console.log(" successfully deleted!");
}).catch(function(error) {
console.error("Error removing document: ", error);
});
});
Thanks

Firebase Cloud Firestore allows you to perform simple and compounded queries. Essentially, you can provide a condition in the db.collection(<COLLECTION>).where() clause which will filter all documents that match that certain condition.
For illustrative purposes, suppose documents in the a collection follow the following structure: { id, '123', name: 'test', color: 'red' }. If you want to get all documents with the color red, you can simply call db.collection('a').where('color', '==', 'red'), which you can then iterate into to process each document that matches that condition.
Moreover, in your specific case, suppose your document structure is { id, content }you can try something like this:
var deleteContent = document.getElementById('delete');
deleteContent.addEventListener('click', function(e) {
// get current document ID
let docToDelete = db.collection("checkin").where('content', '==', 'CONTENT_GOES_HERE')
x = docToDelete.id;
var getId = db.collection("checkin").doc(x);
getId.delete().then(function() {
console.log(" successfully deleted!");
}).catch(function(error) {
console.error("Error removing document: ", error);
});
});
However, a much simpler way would be to store the document id somewhere within your application whenever a specific document is read, local storage or session storage for instance. As such, you can refer to the document id whenever you need. For example, suppose that you fetch all of a user's documents in an onLoad event handler --- suppose that you have HTML elements with the id 'content1', 'content2', 'content3', etc. and that it is where the contents of your documents are shown. You can try something like this:
let userId = 123;
[...].onload = () => {
// Get all of the documents belonging to this user
let i = 0;
let docs = [];
let documents = db.collection('posts').where('userId', '==', userId);
documents.forEach(doc => {
document.getElementById(`content${i}`).innerHTML = JSON.stringify(doc.data()); // Just stringifying to be certain
/**
* Extra step to add the document id in the sessionStorage so that we can refer to it later
*/
htmlId = 'content' + i;
sessionStorage.setItem(htmlID, doc.id );
})
}
In doing so, you can simply refer to the document id like such sessionStorage.getItem('content2').
Note that in any of the examples I listed, there is heavy preparation that needs to be done in order for this to be as smooth sailing as possible. However, wouldn't you agree that a programmer merely is a person that spends hours on things that takes minutes for the sake of making it easier in subsequent uses? :)

Related

Firebase Firestore: How to update or access and update a field value, in a map, in an array, in a document, that is in a collection

Sorry for the long title. Visually and more precise, I would like to update the stock value after a payment is made. However, I get stuck after querying the entire document (e.g. the selected one with title sneakers). Is there a way to actually query and update for example the Timberlands stock value to its value -1. Or do you have to get all data from the entire document. Then modify the desired part in javascript and update the entire document?
Here is a little snippet of a solution I came up with so far. However, this approach hurts my soul as it seems very inefficient.
const updateFirebaseStock = (orders) => {
orders.forEach( async (order) => {
try {
collRef = db.doc(`collections/${order.collectionid}`);
doc = await collRef.get();
data = doc.data();
//Here:const newItems = data.items.map(if it's corr name, update value, else just return object), results in desired new Array of objects.
//Then Update entire document by collRef.update({items: newItems})
} catch (error) {
console.error(error)
};
});
}
You don't need to get the document at all for that, all you have to do is use FieldValue.increment(), using your code as a starting point it could look like this:
collRef = db.doc(`collections/${order.collectionid}`);
collRef.update({
Price: firebase.firestore.FieldValue.increment(-1)
});
You can increment/decrement with any numeric value using that function.

Refilling a form from a database

I'm so stuck on this I might not even be able to formulate a sensible question, but here goes...
I have a gigantic (and occasionally changing) form. I've found a reasonable way to get all the data from the form, turn it into an object, and save it to Firebase all at once. It looks like this, and is working fine (I think):
const incidentReport = document.getElementById('incident-report-form');
let irv = {};
// This works. All form data is saved to an object (as required by firebase), with the question as the name and the answer as the value.
incidentReport.addEventListener('submit', (e) => {
e.preventDefault();
[...incidentReport.elements].forEach((item) => {
let name = item.name;
let value = item.value;
irv = { ...irv, [name]: value };
});
// After all data is collected in one object, I send it to the database all at once.
db.collection('incident reports').add(irv);
});
Okay, so far so good... Now I want to get it back out of the database (I know how to do this) and repopulate the same form (no idea). I'm 100% stumped and I don't even know what to try.
Please forgive me if this is super easy and my brain is just shutting off... it's been a rough day.
Thanks in advance.
EDIT - This seems to work? I'm still very open to criticism and/or improvements.
// Get data from incident reports
//#TODO -> Need to create a list of incident reports, and then load the one //the user clicks on.
//Right now there is only one incident report in the database for testing.
db.collection('incident reports')
.get()
.then((snap) => {
snap.docs.forEach((element) => {
data = element.data(); //Previously declared but not included in this snippet, sorry.
});
for (let [key, value] of Object.entries(data)) {
let x = document.getElementsByName(key)[0];
if (x !== undefined) {
x.value = value;
}
}
});
If I understood it correctly, once you returned the data from your Firestore collection, you want to print them back in your HTML form. Considering that, it should not be very hard for you to achieve that.
Once you load the documents into an array, you should be able to assign the values to variables, that will be printed in the form. It should be something like this:
//Getting the collection and a specific document
var report = db.collection('incident reports').doc('<report>');
var getDoc = report.get()
.then(doc => {
if (!doc.exists) {
console.log('No such document!');
} else {
// Loading the values of the document into variables
var name = getDoc.data().name;
var value = getDoc.data().value;
...
// Other values loaded to other variables that you create
}
})
.catch(err => {
console.log('Error getting document', err);
});
Once you have loaded the values into variables, you just need to create a tag <script> that will be adding the values via Javascript into your HTML. Something that can look like this:
<script src="http://code.jquery.com/jquery-3.4.1.min.js"></script>
document.getElementById('<form item name>').innerHTML = name;
</script>
While this code is not tested, I believe it should be a good starting point for you, on what you need to do, to achieve your goal. It's only for one document, but since you are on tests right now and have only one document, you should be fine.
Besides that, you can find a good and full example on retrieving values from Firestore and priting in a page, in this other post here: How can I display all data from Firestore documents into html elements
Let me know if the information helped you!

SnapshotChanges subscription doesn't detect final deletion of sub-collection item

I have the following code to retrieve some user information from Cloud Firestore - it grabs the list of challenges a user is part of from a subcollection on their user document and then uses those ids to collect the full challenge information from the top level challenge document.
When I delete a challenge I remove it from the main challenges document and then remove the id reference in each users challenges subcollection. The UI updates nicely for each delete as snapshotchanges is an active subscription, until I delete the final one. The final one deletes from the database but stays in the UI until I refresh or make a new challenge.
My theory is that becuase deleting the last document in the challenges subcollection also deletes the subcollection this means snapshotChanges doesn't run as there is no longer a collection in the database to monitor the changes on.
Any thoughts on how to workaround this would be great.
getChallenges() {
return this.getCurrentUserId().pipe(switchMap(userId => {
return this.db.collection(`users/${userId}/challenges`).snapshotChanges().pipe(
map(actions => actions.map(a => {
const data = a.payload.doc.data();
console.log('in get challenges: ', data);
const user_challenge_key = a.payload.doc.id;
return this.getOneChallenge(data['id'], user_challenge_key);
}))
);
}));
}
getOneChallenge(id, user_challenge_key = null): Observable<Challenge> {
return this.db.doc(`challenges/${id}`).snapshotChanges().pipe(
take(1),
map(changes => {
const data = new Challenge(changes.payload.data());
const challengeId = changes.payload.id;
data.user_challenge_key = user_challenge_key;
data.id = id;
console.log('in get One challenge: ', data);
return data;
})
);
}
Maybe maintain a dummy document in order to keep the sub-collection
For example, validate if you going to delete the last element of that sub-collection add the dummy and later delete the last element
for the first insertion check if the dummy object is the only document, after that add your first entry and delete the dummy
I found a similar question with similar approach on the Firestore's Google Group

Trying to check for a certain field inside a firebase firestore document but struggling with the logic behind it

So I am using this currently to check and see if a doc exists for a user
let user = firebase.auth().currentUser;
let userInfo = db.collection("stripe_customers").doc(user.uid);
and then if it does, it runs a script I want
userInfo.get().then(function (doc) {
if (doc.exists) {
However, instead of checking for a specific doc, I need to try and check for a field value inside some documents.
For example I have a collection called "stripe_customers" > that has a document per user via their UID > then inside the document is the collection "charges" > then inside "charges" is a document under a random string of numbers and letters "89nzVNrfQCOVqogDaGvo" for example that is generated by stripe for their charge after they purchase (there may be multiple of these if they have an older charge which is why I need to find the most recent one) > then inside the most recent charge document, I need to check for the field "status" and that is has the value "succeeded". That way I can check to see who has a succeeded payment and if they do it will run the script I want. I am just so confused on how to achieve this. I know how to do basic queries but this is somewhat complex. I need to be able to make sure the current UID has that field with that value so I can see if the current UID paid or not and if they did the script runs, which sets a custom claim.
Here is a visual of my db storage flow for what im trying to do so its easier to understand https://imgur.com/a/NE1x6sU
So, you want to get the most recent document in a charges (sub)collection based on a created field which contains a timestamp value, and check the value of the status field of this doc.
The following should do the trick:
const user = firebase.auth().currentUser;
const subCollRef = db.collection("stripe_customers").doc(user.uid).collection("charges");
const query = subCollRef.orderBy('created', 'desc').limit(1);
query.get()
.then(snapshot => {
if (snapshot.size > 0 && snapshot.docs[0].data().status === "succeeded") {
//payment was succeeded, you can "run your script"
});
})
.catch(err => {
console.log('Error getting documents', err);
});

How to make doc.id clickable item?

How can I turn doc.id into clickable item?
Right now I can get data from my database, I can list all the doc.id's, but I want to make those into hyperlinks, when pressed it gets the data from the database and shows it's data as a drawing on the canvas. If that makes sense?
doc.id is that unique id for stuff that is saved in my firestore db.
const allDrawings = document.querySelector('#allDrawings');
function renderDrawings(doc){
let li = document.createElement('li');
let key = document.createElement('doc.id');
li.setAttribute('data-id', doc.id);
key.textContent = doc.id;
li.appendChild(key);
allDrawings.appendChild(li);
}
db.collection('joonistused').get().then((snapshot) => {
snapshot.docs.forEach(doc => {
renderDrawings(doc);
console.log(doc.id);
})
})
If you're just trying to create an anchor in the DOM then try something like this:
const anchor = document.createElement('a');
anchor.href = `/some/path/to/${doc.id}`;
anchor.innerText = `Document ID ${doc.id}`;
// Document ID 123
I believe what you are looking for is a design/logic to list documents in a firestore collection in your browser and make them list items. You then want to click on an item and have the content for that document displayed to the user. This will require programming logic on your end. You will want to write browser/client side JavaScript that is called when a link is clicked (onclick). When the JavaScript code is reached you will then want to make a web client call to the Firestore database to retrieve the corresponding document.
See: https://firebase.google.com/docs/reference/js/firebase.firestore.DocumentReference.html#get
This looks very useful too:
Firebase Firestore Tutorial #3 - Getting Documents

Categories

Resources