Firestore setDoc Function not merging new items on React JS - javascript

so I'm trying to have this function "Walletwrite" check if a document already exists, then if document doesn't exist, creates a new one with the values I want to add, or updates an existing document by adding a new field with those new values. All of this on React JS.
However, my setDoc function is actually overwriting existing data if document already exists..
Any ideas on where the problem is?
async function Walletwrite() {
//These first 2 consts check if the entry is already in that specific document to prevent duplicates.
const marketRef = db.collection("marketplace");
const query = marketRef.where("wallet", "array-contains", account).where("item", "==", item.id).limit(1);
query.get().then((snapshot) => {
if (snapshot.empty == false) {
console.log(snapshot)
return
}
else{
//This is where it gets tricky and merge: true is not working
const walletRef = doc(db, 'marketplace', item.id);
setDoc(walletRef, {item: item.id, wallet: account} , { merge: true });
}
});
}
Trying different firestore functions but none of them seem right to my use case, except this setDoc with merge: true..

Related

Query Nested Object in Firebase Firestore

I have in my Firestore database a list of documents that include this field 'Participants', as a nested object.
I want to make a query that gets only one document from the database (to see if it exists or not) that has (for example) user id 5 and 6.
This is what my code looks like
const chatsCollection = db.collection('chats');
async function createChat(myId, otherUserId){
chat = await chatsCollection
.where(`participants.${myId}`, "==", true)
.where(`participants.${otherUserId}`, "==", true)
.limit(1).get();
if(!chat.exists){
alert('chat doesnt exist')
//create chat
} else {
alert('chat exists')
//do something else
}
}
However, even if the chat with the participants object does indeed exist in the database, the result of the code indicates that it doesn't.
Here is the structure of the data when it is added to the database
var chat_key = (Math.random() + 1).toString(36).substring(2);
chatData = {
key: chat_key,
created_at: new Date(),
participants: {
myId: true,
otherUserId: true,
}
}
chatsCollection.doc(chat_key).set(chatData);
I appreciate any help on how to solve this problem.
Thanks :)
on method collection, you can use empty property to see if the query getting data or not
if(chat.empty){
alert('chat doesnt exist')
//create chat
} else {
alert('chat exists')
//do something else
}
to get only one document from your query, you can use
chat.docs[0].data();

Firebase: how to create nested object

There are questions on how to update nested properties for a Firebase record, but no answers on how to create records with nested properties.
This and this were similar but did not help.
From the web, the goal is to create a Firebase record with nested properties.
Using dot notation works for updates, but a nested hierarchy doesn't get created when reusing the same key for creating the record.
Which makes sense because the key doesn't impart any information about the data types of the child properties.
What is the right way to create an object with nested properties?
async test(serviceId, numCredits, emailAddress) {
// Set credits key.
let creditsKey = `credits.${serviceId}.numAllowed`;
try {
// Get user matching #emailAddress.
let user = await this.getUser(emailAddress);
// New user? Create database record.
if (!user) {
this.db_
.collection('users')
.add(
{
emailAddress: emailAddress,
[{creditsKey}]: numCredits
}
);
// Nope, user exists so update his/her record.
} else {
// Set update query.
let query = this.db_
.collection('users')
.where('emailAddress', '==', emailAddress);
// Run update query.
const querySnapshot = await query.get();
return querySnapshot.docs[0].ref.update({
[creditsKey]: firebase.firestore.FieldValue.increment(numCredits)
});
}
} catch(e) {
debug('Error in test(): ' + e);
}
}
If I correctly understand your question, the following would do the trick. (There are probably more elegant solutions however...)
const obj = {};
obj.numAllowed = numCredits;
const obj1 = {};
obj1[serviceId] = obj;
// ...
this.db_.collection('users')
.add(
{
emailAddress: emailAddress,
credits: obj1
})

Firestore retrieve single document by field value and update

I'm trying to retrieve a single document by a field value and then update a field inside it.
When I do .where("uberId", "==",'1234567'), I am getting all the docs with field uberId that matches 1234567.
I know for sure there is only one such document. However, I don't want to use uberId as the document's ID, otherwise I could easily search for the document by ID. Is there another way to search for a single document by a field ID?
So far, reading the docs, I could see this:
const collectionRef = this.db.collection("bars");
const multipleDocumentsSnapshot = await collectionRef.where("uberId", "==",'1234567').get();
Then I suppose I could do const documentSnapshot = documentsSnapshot.docs[0] to get the only existing document ref.
But then I want to update the document with this:
documentSnapshot.set({
happy: true
}, { merge: true })
I'm getting an error Property 'set' does not exist on type 'QueryDocumentSnapshot<DocumentData>'
While you may know for a fact there's only one document with the given uberId value, there is no way for the API to know that. So the API returns the same type for any query: a QuerySnapshot. You will need to loop over the results in that snapshot to get your document. Even when there's only one document, you'll need that loop:
const querySnapshot = await collectionRef.where("uberId", "==",'1234567').get();
querySnapshot.forEach((doc) => {
doc.ref.set(({
happy: true
}, { merge: true })
});
What's missing in your code is the .ref: you can't update a DocumentSnapshot/QueryDocumentSnapshot as it's just a local copy of the data from the database. So you need to call ref on it to get the reference to that document in the database.
async function getUserByEmail(email) {
// Make the initial query
const query = await db.collection('users').where('email', '==', email).get();
if (!query.empty) {
const snapshot = query.docs[0];
const data = snapshot.data();
} else {
// not found
}
}

Angular Firestore query with where returns all docs in collection

I have an angular app that is using Firestore. Whenever I query for docs in collection that meet a specific condition, the array that is returned contains every document in the collection. I do not understand why this is happening as I am following the documentation.
On call to the collection in the component
this.FirebaseService.getDocsByParam( 'versions', 'projectId', this.projectData.uid )
.then((snapshot) => {
var tempArray = [];
var docData;
snapshot.forEach((doc) => {
docData=doc.data();
docData.uid=doc.id;
tempArray.push(docData);
});
this.versionList = tempArray;
this.versionData = this.versionList[this.versionList.length-1];
this.initializeAll();
})
.catch((err) => {
console.log('Error getting documents', err);
});
Firebase service making the call
getDocsByParam( collection, getParam:string, paramValue:string ) {
var docRef = this.afs.collection(collection, ref => ref.where(getParam, '==', paramValue));
return docRef.ref.get();
}
Below is a screen shot of the versions collection. It shows one of the returned docs, which does not even have the required field.
When you call docRef.ref on a AngularFirestoreCollection it returns the underlying collection, not the query. So your return docRef.ref.get() is indeed getting the entire collection.
I think you can use docRef.query to get the query, but I don't even thing there's any reason to use an AngularFire call at all here. Since your code is already using the plain JavaScript API to process the documents, you might as well stick to that SDK in your getDocsByParam too:
getDocsByParam( collection, getParam:string, paramValue:string ) {
var docRef = this.afs.collection(collection).ref;
return docRef.where(getParam, '==', paramValue).get();
}

Firestore can't get empty docs

I have collection of documents where the id of the doc is the users id.
Lets call these user documents.
Each "user document" contains a subcollection of chat messages. But not all "user documents" contains any fields (data, other than the subcollection).
I wan't to return all the doc in the collection that don't have any fields, but have a subcollection, but I seems this is not possible?
var allUserDocs = {},
count = 0,
users = firestore.collection("users");
users.get().then(snapshot => {
snapshot.forEach(doc => {
count++;
allUserDocs[count] = doc.data();
});
allUserDocs.count = count;
res.status(200).send(allUserDocs);
})
this code only returns the docs that contains fields, not the docs that only have a subcollection? Is there a way to return all?
How can i get a list of all document ids in the collection? both empty and non-empty ones? or how can I add a field to all the docs without fields if i cant access them?
There is a listDocuments method that retrieves all documents, missing or not, that have a subcollection. Here's the page in the docs that explains it.
Something like this might be what you are looking for:
let collectionRef = firestore.collection('col');
return collectionRef.listDocuments().then(documentRefs => {
return firestore.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}`);
}
}
});
You would not care whether the docRef exists or not.
Nevertheless, it does not sound like a good solution to have empty documents. What is the logic you were pursuing with an architecture where users can be empty, but messages underneath them still matter? Maybe if you still need to access them you can add a boolean variable to determine if the user is active or not, instead of leaving a blank document.
Use doc.id
users.get().then(snapshot => {
snapshot.forEach(doc => {
count++;
allUserDocs[doc.id] = doc.data();
});
allUserDocs.count = count;
res.status(200).send(allUserDocs);
})

Categories