React Firebase Snapshot retrieve all children - javascript

So I've been scratching my head for a while now over a function that I can't seem to make work in React. I'm creating this basic file manager with the Firebase storage and the Cloud Firestore.
What I'm trying to do is to fetch all children in "files", but in this very process also run a function within the fetching process grabbing the file uploaders name and then push it to my array so I can display the file list with correct information instead of showing an id of the file owner. This is the code that I have so far:
export const retrieveLibrary = () => {
return new Promise((resolve, reject) => {
fetchCompanyId().then((companyId) => {
var allFiles = [];
database.collection("files").orderBy("uploadDate").get().then((snapshot) => {
if(!snapshot.empty){
snapshot.forEach((singleSnapshot) => {
fetchFileOwner(singleSnapshot.data().owner).then((name) => {
allFiles.push({key: singleSnapshot.id, downloadLink: singleSnapshot.data().downloadLink, name: singleSnapshot.data().name, type: singleSnapshot.data().type, uploadDate: singleSnapshot.data().uploadDate, password: singleSnapshot.data().password ? true:false, owner: name});
})
})
resolve(Promise.all(allFiles));
}
}).catch((e) => {
reject(e);
})
})
})
}
Here I'm basically doing everything connected with Firebase and trying to create an array that I can retrieve from a promise.
export const fetchFileOwner = id => {
return new Promise((resolve, reject) => {
database.collection("users").doc(id).get().then((userInfo) => {
resolve(userInfo.data().firstName);
}).catch((e) => {
reject(e);
})
})
}
Pretty simple, grabbing the users first name.
fetchLibraryFiles().then((library) => {
setLibraryFiles(library);
}).catch((e) => {
console.log(e);
})
This is the function I'm calling to retrieve the full library. As you can probably see, I have tried my best to find a way to do this, but I am not able to retrieve the full array. However, when I remove the fetchFileOwner function call inside retrieveLibrary - it works. What am I doing wrong here and why is it wrong? What is the best way of doing something like this where I have to call other functions and wait for the data retrieved?
Help is greatly appreciated.
Data format is here:
the owner is just a UID tied to an account.

Related

Create an array whenever an image is uploaded using url and then store a object into that array in firestore

I am able to get url, caption and id of an image using an object and then store them into firestore field but the problem is, I need them to be stored into an array so I can retrieve and display the images onto my UI. Currently firestore field is returning an array
I tried to merge class object with an array, push the object into the array and using normal object instead of class object.
`
class App {
constructor() {
this.posts = [];
this.post = {
id: cuid(),
caption: "",
image: "",
};
getFileUrl(name) {
const imageRef = storage.ref(name);
imageRef
.getDownloadURL()
.then((url) => {
this.post.image = url;
console.log(this.post.image);
this.savePosts();
this.render();
})
.catch((error) => {
console.log(error, "Error Occured");
});
}
savePosts() {
db.collection("users")
.doc(this.userId)
.set({
post: this.posts,
})
.then(() => {
console.log("Document successfully written!");
})
.catch((error) => {
console.error("Error writing document: ", error);
});
}
render() {
this.savePosts();
}
`
firestore
If think you're looking for:
this.post.image.push(url);
If you tried that and ran intro problems, edit your question to show the exact code you tried and where you got stuck (including any error message or the erroneous result you got).

Reading a value from Realtime Firebase

I have the following json structure:
Within "all" node I have an attribute "drinkId" and I'm trying to move it outside that child node bringing it one level up.
I'm trying to read the value without any luck
const cocktailRef= firebase
.database()
.ref("Ratings");
cocktailRef.once("value", (snapshot) => {
snapshot.forEach((child) => {
const drinkIdPass = child.ref.child("all").child("drinkId").value();
child.ref.update({ drinkId: drinkIdPass });
})
})
I've tried different variants of ".value()", same problem
There isn't any value() method on a DataSnapshot. It's val() Try refactoring your code like this:
const cocktailRef= firebase.database().ref("Ratings");
cocktailRef.once("value").then(async (snapshot) => {
const updates = { }
snapshot.forEach((child) => {
const drinkIdPass = child.val().all.drinkId
updates[`${child.key}/drinkId`] = drinkIdPass
})
await cocktailRef.update(updates)
console.log("Data updated")
})

use external functions in the componentDidMount() and pass an element of the state to them as parameter

I have a big application in React-Native and I have a lot of duplicate functions in the code.
So I created a file called function.js which could contain all my duplicate functions. Like queries on the local database, remote data base...
So I pretty much got the job done. However I have a problem.
This two functions must be used one after the other.
The first one does an update of the state to get a user id from local database.
The second one, asks information from the remote database with the user id retrieved by the first function in parameters.
When both calls are in the componentdidmount element, unfortunately it doesn't work !!
The update time of the state by the first function is too slow compared to the execution of the second function.
The second function gets an "undefined" parameter when it is executed. because the state is not updated by the first function for the moment.
If I put the second function in componentDidUpdate() it works but it runs in a loop so it's not a solution either.
I also don't want to trigger the execution of the second function at the end of the first one in the external file. It would make the functions not autonomous from each other.
And I think that the solution of a timeout() is not very good either, even if we could work with it.
Example code :
It's the content of my App.js file that imports the Function.js file containing all my functions
import React, { Component } from 'react';
import { fetchUser, prepareUserData } from 'bitcoin/Functions/Function'
export default class Profile extends Component {
state = {
user_id: "",
}
componentDidMount() {
fetchUser.call(this);
prepareUserData.call(this, this.state.user_id)
}
render{
return (<View></View>)
}
This is the content of my Function.js file which contains functions that are duplicated in my application.
import * as SQLite from "expo-sqlite";
import axios from "axios";
const db = SQLite.openDatabase("db.db");
/* #############################################################################
User data retrieval function in the local database
##############################################################################*/
export function fetchUser () {
let query = "select * from ?";
let params = [];
db.transaction(tx => {
tx.executeSql(
query,
params,
(_, { rows: { _array } }) => {
this.setState({user_id: _array[0].user_id})
},
function(tx, err) {
console.log("Erreur" + err);
}
);
});
}
/* #############################################################################
User data retrieval function in the remote database
##############################################################################*/
export function prepareUserData(userID) {
let userConnect = new FormData();
userConnect.append("id", userID);
console.log(userConnect)
const url =
"https://*************/rest_api/React_native_api/appmobile_profile";
axios
.post(url, userConnect)
.then(res => {
console.log(res.data)
if(res.status === 200){
this.setState(
{
user_pseudo: res.data.pseudo,
[ ... ]
user_lastName: res.data.last_name,
},);
}
})
.catch(err => {
console.log("Erreuur", err);
});
}
I've tried a lot of things with async componentDidMount(), await myfunc(), creating asynchronous functions in my function file ...
But I can't find solutions. I could do otherwise but I find the problem really interesting.
I think there is a way to optimize my use of react native.
Thank you for your various feedbacks. Have a nice day.
Okay, so I've come up with a effective solution to this problem.
I don't know much about promise and yet it seems to be a key for a lot element in react-native and javascript in general.
I'll share my code. Hopefully it can be useful to someone in the future! thank you for your prompt return and see you soon!
To make it work I used:
The Promise Object new Promise(function(resolve,reject)
Creation of a dynamic SQL query by adding parameters when calling the function.
File App.js
import React, { Component } from 'react';
import { selectFromTable, prepareUserData } from 'bitcoin/Functions/Function'
export default class Profile extends Component {
state = {
user_data: "",
}
componentDidMount() {
selectFromTable('user', ['*']).then((result) => {
this.setState({ user_data: result.rows._array[0] },() =>
{prepareUserData.call(this, this.state.user_data.user_id)})
})
}
render{
return (<View></View>)
}
File Function.js
export function selectFromTable(table_name, selected_columns, conditions, callback) {
return new Promise(function(resolve,reject) {
let db_cmd = `SELECT ${selected_columns} FROM ${table_name}`;
db.transaction((tx, err) => {
tx.executeSql(db_cmd, [], (tx, res) => {
resolve(res);
},
function(tx, err) {
console.log("Error" + err);
}
);
});
});
}
export function prepareUserData(userID) {
let userConnect = new FormData();
userConnect.append("id", userID);
const url =
"https://**********/**********/appmobile_profile";
axios
.post(url, userConnect)
.then(res => {
console.log(res.data)
if(res.status === 200){
this.setState(
{
user_pseudo: res.data.pseudo,
user_cellphone: res.data.cellphone,
user_callingCode: res.data.calling_code,
});
};
})
.catch(err => {
console.log("Error", err);
});
}

Add Payment source to Stripe with firebase-cloud-functions?

I'm trying to integrate stripe payment with my firestore firebase database. I'm having trouble figuring out add payment source function given in the firebase doc example. What am I missing here?
exports.addPaymentSource = functions.firestore
.document('Customers/{userId}/paymentSources/{paymentId}')
.onWrite((change, context) => {
let newPaymentSource = change.after.data();
if (newPaymentSource === null){
return null;
}
return admin.firestore().collection("Customers").doc(`${context.params.userId}`).get('customer_id')
.then((snapshot) => {
return snapshot.val();
}).then((customer) => {
return stripe.customers.createSource(customer, {newPaymentSource});
}).then((response) => {
return change.after.ref.parent.set(response);
}, (error) => {
return change.after.ref.parent.child('error').set(userFacingMessage(error));
}).then(() => {
return reportError(error, {user: context.params.userId});
});
});
I tried
console.log(snapshot.val())
and it gives me a type error.
Firestore database Image
Error Log Image
You're reading from Cloud Firestore, yet are using variable names and method calls that are for the Realtime Database. While both databases are part of Firebase, they're completely separate, and have different APIs.
The equivalent code for Firestore would be:
return admin.firestore().collection("Customers").doc(`${context.params.userId}`).get()
.then((doc) => {
return doc.data();
}).then((customer) => {
...
Also see:
the documentation on reading a document

Cloud Functions for Firebase: how to use a Transaction promise?

I am trying to write a function in Cloud Functions that triggers every time a user gets created and which then saves that user into a list of users and finally increments a user counter.
However I am not sure if I am using promises correctly.
exports.saveUser = functions.auth.user().onCreate(event => {
const userId = event.data.uid
const saveUserToListPromise = db.collection("users").doc(userId).set({
"userId" : userId
})
var userCounterRef = db.collection("users").doc("userCounter");
const transactionPromise = db.runTransaction(t => {
return t.get(userCounterRef)
.then(doc => {
// Add one user to the userCounter
var newUserCounter = doc.data().userCounter + 1;
t.update(userCounterRef, { userCounter: newUserCounter });
});
})
.then(result => {
console.log('Transaction success!');
})
.catch(err => {
console.log('Transaction failure:', err);
});
return Promise.all([saveUserToListPromise, transactionPromise])
})
I want to make sure that even if many users register at once that my userCounter is still correct and that the saveUser function won't be terminated before the transaction and the save to the list has happened.
So I tried this out and it works just fine however I don't know if this is the correct way of achieving the functionality that I want and I also don't know if this still works when there are actually many users triggering that function at once.
Hope you can help me.
Thanks in advance.
The correct way to perform multiple writes atomically in a transaction is to perform all the writes with the Transaction object (t here) inside the transaction block. This ensures at all of the writes succeed, or none.
exports.saveUser = functions.auth.user().onCreate(event => {
const userId = event.data.uid
return db.runTransaction(t => {
const userCounterRef = db.collection("users").doc("userCounter")
return t.get(userCounterRef).then(doc => {
// Add one user to the userCounter
t.update(userCounterRef, { userCounter: FirebaseFirestore.FieldValue.increment(1) })
// And update the user's own doc
const userDoc = db.collection("users").doc(userId)
t.set(userDoc, { "userId" : userId })
})
})
.then(result => {
console.info('Transaction success!')
})
.catch(err => {
console.error('Transaction failure:', err)
})
})

Categories

Resources