How can I update a document found in a query? - firebase

I want to update document found by a query. Actually I'm trying the following approach:
export const add_user = functions.https.onRequest((request, response) => {
corsHandler(request, response, () => {
const collectionReference = db.collection("users");
const query = collectionReference.where("name", "==", "John");
fbid_query.get()
.then(function(querySnapshot) {
if (querySnapshot.empty) {
console.log("John notfound");
} else {
console.log("John found!");
querySnapshot.forEach(function (documentSnapshot) {
add_update(query, "George");
});
}
response.json([]);
})
.catch(function(error) {
response.json([]);
});
});
});
.
const add_update = function (query, new_name) {
query.get(function(querySnapshot) {
querySnapshot.forEach(function(document) {
console.log("entered in forEach");
document.ref.update({
name: new_name
});
});
}).then(function () {
console.log("success");
})
.catch(function(error) {
console.error("error: ", error);
});
}
The only console.log that appears is success, although nothing is updated and John indeed exists in Cloud Firestore.
What am I doing wrong?
PS: I don't know if it matters but before I actually try to update, I call query.get() just to check if something exists (and after I call that approach to update).

Related

How to get multiple references in a firestore snapshot

I have a firestore collection containing post documents, each document contains a reference to an author (user) and a case document.
How do I get the user and the case in the same onSnapshot?
Here's what I'd like to do with await, but that doesn't seem to be an option with react-native-firebase.
export const firebasePostLooper = (snapshot) => {
let data = [];
snapshot.forEach(async (doc) => {
let newItem = {id: doc.id, ...doc.data()};
if (newItem.author) {
let authorData = await getDoc(newItem.author); // doesn't work with rnfirebase
if (authorData.exists()) {
newItem.userData = {userID: authorData.id, ...authorData.data()};
}
}
if (newItem.case) {
let caseData = await getDoc(newItem.case);
if (caseData.exists()) {
newItem.userData = {userID: caseData.id, ...caseData.data()};
}
}
data.push(newItem);
});
return data;
};
This doesn't work because getDoc() doesn't exist.
So I'm left with using .then()
export const firebasePostLooper = (snapshot) => {
let data = [];
snapshot.forEach((doc) => {
let newItem = {id: doc.id, ...doc.data()};
if (newItem.author) {
newItem.author
.get()
.then((res) => {
newItem.authorData = res.data();
if (newItem.case) {
newItem.case
.get()
.then((caseRes) => {
newItem.caseData = caseRes.data();
data.push(newItem);
})
.catch((err) => console.error(err));
}
})
.catch((err) => console.error(err));
} else {
data.push(newItem);
}
});
return data;
};
This second method doesn't seem to be working, data is empty at the return statement but data.push(newItem) contains the correct document with the 2 referenced documents.
You're returning data before it gets filled inside the promise. You should handle the returning of the data inside a .then() in order to return it after the promise has resolved and not before.
Take a look at this example where if we handle the emptyData object outside the promise chain, we just return the initial value before it has been filled.
let promise = new Promise((resolve, reject)=>{
setTimeout(resolve, 1000, 'foo');
})
let emptyData= [];
let notEmptyData = [];
promise
.then(res=>{
emptyData.push(res);
notEmptyData.push(res);
console.log("Full data: " + notEmptyData) // "Full data: foo"
});
console.log("Empty data: " + emptyData); // "Empty data: "

Firebase Cloud Function I want to change all user data

exports.scheduledFunctionCrontab = functions.pubsub.schedule('5 20 * * *')
.timeZone('Asia/Seoul') // Users can choose timezone - default is America/Los_Angeles
.onRun((context) =>
{
var allUsers = [];
return admin.auth().listUsers()
.then(function (listUsersResult)
{
listUsersResult.users.forEach(function (userRecord)
{
// For each user
var userData = userRecord.toJSON();
allUsers.push(userData.uid);
console.log(allUsers);
});
//res.status(200).send(JSON.stringify(allUsers));
}).then(function ()
{
allUsers.forEach(function (elem)
{
db.ref(`Data/${elem}/Enter`).update({ test: 0, test2: 0 });
});
})
.catch(function (error)
{
console.log("Error listing users:", error);
//res.status(500).send(error);
});
});
By getting the UIDs of all users at a specific time
I want to change the data with UID as parent But An error has occurred
Each then() should return a value or throw promise/always-
Could you please let me know what's wrong with my code?
Maybe try adding a return statement to each then block like so:
return admin.auth().listUsers()
.then(function (listUsersResult)
{
listUsersResult.users.forEach(function (userRecord)
{
// For each user
var userData = userRecord.toJSON();
allUsers.push(userData.uid);
console.log(allUsers);
});
return true; //<--------------- add this return statement
}).then(function ()
{
allUsers.forEach(function (elem)
{
db.ref(`Data/${elem}/Enter`).update({ test: 0, test2: 0 });
});
return true; //<--------------- add this return statement
})
.catch(function (error)
{
console.log("Error listing users:", error);
//res.status(500).send(error);
});

React native cannot set multiple arrayitems from Firebase in loop

I am trying to get data from Firebase realtime database in the loop and set array items,
but just the last item can set.
it's looking like synchronize problems I tried a lot of things but couldn't solve it.
import FireBaseConnection from '../classes/firebaseconnection.js';
const getComments = () => {
let cardatafetch=[]
FireBaseConnection.GetData('/PostComments/1234').then((comments) => {
for (i in comments) {
cardatafetch.push(comment[i])
}
for (j in cardatafetch) {
var UserId = cardatafetch[j]["UserID"]
FireBaseConnection.GetData('/Users/'+UserId).then((user) => {
cardatafetch[j].ProfilePicture=user["ProfilePicture"]
})
.catch((error) => {
console.log(error)
});
}
console.log(cardatafetch)
}).catch((error) => {
console.log(error)
});
}
}
Console Output is
Same problem also during get images from storage
for (j in cardatafetch) {
FireBaseConnection.GetImage().then((obj) => {
cardatafetch[j].ProfilePicture=obj
})
.catch((error) => {
console.log(error)
});
}
FireBaseConnection Class
import database from '#react-native-firebase/database';
import storage from '#react-native-firebase/storage';
import { utils } from '#react-native-firebase/app';
class FireBaseConnection
{
static async GetData(refValue) {
let data;
await database()
.ref(refValue)
.once('value')
.then(snapshot => {
data = snapshot.val();
});
return data;
}
static async GetImage(imgValue) {
const reference = storage().ref(imgValue);
let imagePath= await reference.getDownloadURL().then(result =>result);
return imagePath;
}
}
export default FireBaseConnection;
Try below code, what I have done is put your code inside last iteration of the loop so it will be implemented only once when all the items are pushed in the array.
import FireBaseConnection from '../classes/firebaseconnection.js';
const getComments = () => {
return new Promise((resolve, reject) => {
let commentsArr = [];
FireBaseConnection.GetData('/PostComments/1234').then((comments) => {
Object.keys(comments).forEach((key, index) => {
commentsArr.push(comments[key])
if(index == Object.keys(comments).length-1) {
resolve(commentsArr);
}
});
}).catch((error) => {
console.log(error)
});
});
}
const addImagesToComment = () => {
this.getComments().then((comments) => {
var finalArr = [];
comments.forEach((comment, index) => {
var tempComment = comment;
var UserId = comment["UserID"]
FireBaseConnection.GetData('/Users/' + UserId).then((user) => {
tempComment.ProfilePicture = user["ProfilePicture"]
finalArr.push(tempComment);
}).catch((error) => {
console.log(error)
});
if(index == comments.length-1) {
console.log(finalArr)
}
});
});
}
Try calling getComments function.

Add Firebase image URL to my collection

I have the following method I'm accessing when my VueJS component is loading:
getServices () {
fb.servicesCollection.get().then(querySnapshot => {
this.serviceList = []
querySnapshot.forEach(doc => {
const { name, icon } = doc.data()
fb.storage.ref().child(icon).getDownloadURL().then(function (url) {
console.log(url)
})
this.serviceList.push({id: doc.id, name: name, icon: 'iconURL'})
})
this.isLoading = false
}).catch(error => {
console.log(error)
})
}
What I want to achieve is to get the url to replace the current 'iconURL' string. Didn't find any method to do that in the last couple of hours. Please help!
The following should do the trick. (However note that I could no test it, so it may need a bit of fine tuning... You can report how it works in the comments and we correct it if necessary)
Since you want to execute several getDownloadURL() asynchronous calls to Firebase Storage in parallel, you have to use Promise.all(), since getDownloadURL() returns a promise, see the doc.
getServices () {
let namesArray = []
let docIdArray = []
fb.servicesCollection.get().then(querySnapshot => {
this.serviceList = []
let promises = []
querySnapshot.forEach(doc => {
const icon = doc.data().icon;
promises.push(fb.storage.ref().child(icon).getDownloadURL())
namesArray.push(doc.data().name)
docIdArray.push(doc.id)
})
return Promise.all(promises)
})
.then(results => {
results.forEach((value, index) => {
this.serviceList.push({id: docIdArray[index], name: namesArray[index], icon: value})
})
})
}).catch(error => {
console.log(error)
})
}
This is how I got it in the end...
getServices () {
fb.servicesCollection.get().then(querySnapshot => {
this.serviceList = []
querySnapshot.forEach(doc => {
const { name, icon } = doc.data()
fb.storage.ref(icon).getDownloadURL().then(url => {
this.serviceList.push({id: doc.id, name: name, icon: url})
})
})
this.isLoading = false
}).catch(error => {
console.log(error)
})
}
Thank you for all your efforts to help me!!! Highly appreciate it!

Update data if exist in firebase

I'm trying to update a data if it exists
var ref = firebase.database().ref().child('users');
var refUserId = firebase.database().ref().child('users').orderByChild('id').equalTo(Auth.$getAuth().uid);
refUserId.once('value', function (snapshot) {
console.log(snapshot);
if (snapshot.exists()) {
snapshot.ref().update(vm.user_infos);
} else {
ref.push({
player: vm.user_infos.player,
id: vm.user_infos.id
}, function(error) {
console.log(error);
})
}
});
Push is working fine, but the update did not.
snapshot.ref is not a function
In the snapshot () log console:
I tried this way too:
if (snapshot.exists()) {
refUserId.update({
player: vm.user_infos.player,
id: vm.user_infos.id
}, function(error) {
console.log(error);
})
Result:
refUserId.update is not a function
User structure
The first problem is that the snapshot's ref property is an object - not a function.
The second is that the snapshot refers to the users path, so you should check for a user that matches your query like this:
var ref = firebase.database().ref().child('users');
var refUserId = ref.orderByChild('id').equalTo(Auth.$getAuth().uid);
refUserId.once('value', function (snapshot) {
if (snapshot.hasChildren()) {
snapshot.forEach(function (child) {
child.ref.update(vm.user_infos);
});
} else {
snapshot.ref.push({
player: vm.user_infos.player,
id: vm.user_infos.id
});
}
});
And if you want to know when the update or push has completed, you could use promises:
refUserId
.once('value')
.then(function (snapshot) {
if (snapshot.hasChildren()) {
return snapshot.forEach(function (child) {
child.ref.update(vm.user_infos);
});
} else {
return snapshot.ref.push({
player: vm.user_infos.player,
id: vm.user_infos.id
});
}
})
.then(function () {
console.log('update/push done');
})
.catch(function (error) {
console.log(error);
});

Resources