I'm doing around 100 writes to Firestore offline. But after connecting to the internet I see some of my data is missing in the cloud. There are no errors in the writing process though.
If I do the same thing online, all the data is synced to the cloud.
Below is the code I'm trying in offline mode. Each function has around 10 iterates. There are 10 functions running one after the other.
const updateCities = async (cities) => {
for (const city of cities) {
try {
const firebaseCity = await firestore().collection('cities').doc(city.id).get();
await firebaseCity.update(city);
} catch (error) {
console.log(error);
}
}
}
const updateUsers = async (users) => {
for (const user of users) {
try {
const firebaseUser = await firestore().collection('users').doc(user.id).get();
await firebaseUser.update(user);
} catch (error) {
console.log(error);
}
}
}
Are there any limitations in the firebase functionalities or I'm doing something wrong?
Related
CURRENTLY
I have the following function IN AWS that utilise Textract SDK async functions:
async function textParse(config) {
const AWS = require("aws-sdk");
let textract = new AWS.Textract();
let analysisResults;
console.log("Before Try");
try {
console.log("Start Document Analysis");
analysisResults = await textract
.startDocumentAnalysis(config, function (err, data) {
if (err) {
console.log("There was an error during doc analysis...");
console.log(err, err.stack);
} // an error occurred
else {
console.log("Doc analysis successful!");
console.log(data);
return data;
} // successful response
})
.promise();
} catch (e) {
throw "Doc Analysis Error!" + e;
}
let JobId = analysisResults["JobId"];
let textractResult = await textract
.getDocumentAnalysis({ JobId: JobId })
.promise();
console.log("End!")
return textractResult;
}
ISSUE
The console log is showing that analysisResults is being calculated twice. Note Doc analysis successful! appearing twice in the logs.
INFO Before Try
INFO Start Document Analysis
INFO Doc analysis successful!
INFO { JobId: '3a1e00c9b5ca9123124hhfdfdsdd02f2053c38ec5249e822c9e95f' }
INFO Doc analysis successful!
INFO { JobId: '5ef298d3a9123124hhfdfdsddsdssdsdsdds689580642a6346' }
INFO End!
I've spent a few hours trying to debug this and I suspect it's something to do with how I'm handling promises.
Any ideas on what changes I need to make?
Don't know the textract library, but this is what the OP code appears to be trying to say in a singular (promise, not callback) style.
async function textParse(config) {
const AWS = require("aws-sdk");
let textract = new AWS.Textract();
console.log("Before Try");
try {
console.log("Start Document Analysis");
let analysisResults = await textract
.startDocumentAnalysis(config)
.promise();
console.log("Doc analysis successful!", analysisResults);
let textractResult = await textract
.getDocumentAnalysis({ JobId: analysisResults["JobId"] })
.promise();
console.log("End!", textractResult);
return textractResult;
} catch (err) {
console.log("There was an error during doc analysis...");
console.log(err, err.stack);
}
}
I worry about answering this way, because it doesn't seem to address the symptom described (two success logs), but even if there's another problem in the code, I think this is still a valid rewrite, form-wise.
I'm adding the claim to a user's profile that he or she paid for something, though, after the payment this attribute isn't visible. I'm running the functions on an emulator on a local host.
This is the code I'm using:
If the paypal function has been handled succesfully through paypalHandleOrder, then the function addPaidClaim is invoked.
onApprove: (data, actions) => {
paypalHandleOrder({ orderId: data.orderID }).then(
addPaidClaim(currentUser).then(
alert("THANKS FOR ORDERING!"),
// currentUser.getIdTokenResult().then(idTokenResult => {
// console.log(idTokenResult.claims)
// })
)
.catch((err) => {
return err;
})
);}
addPaidClaim is a firebase cloud function, which goes as follows:
exports.addPaidClaim = functions.https.onCall((data, context) => {
// get user and add custom claim (paid)
return admin.auth().setCustomUserClaims(data.uid, {
paid: true,
}).then(() => {
return {
message: `Success! ${data.email} has paid the course`,
};
}).catch((err) => {
return err;
});
});
I've refreshed the page and checked the user attributes afterwards through console.log on the user to see if the attribute had been added, but this is not the case. I can't find attribute paid inside the idTokenResult object. What should I do? I also find it hard to make sense of what's happening inside the function addPaidClaim. It's not returning an error when I look at the logs on my firebase console, and not much information is given, besides that the function has been invoked.
Okay, I know this question is pretty old. But I found a way just yesterday after 3 days searching over the solution. After we set up a new claim for a new user using, we need to refresh the client's getIdTokenResult(true) in the app. These are the ways I did it in Flutter Dart until a new user with updated claim managed to use it:
FirebaseAuth auth = FirebaseAuth.instance;
Future<Map<String, dynamic>> signInWithGoogle() async {
Map<String, dynamic> output = {};
final googleUser = await googleSignIn.signIn();
if (googleUser == null) {
log("Firebase => Gmail account doesn't exist");
} else {
final googleAuth = await googleUser.authentication;
final credential = GoogleAuthProvider.credential(
idToken: googleAuth.idToken,
accessToken: googleAuth.accessToken,
);
await auth.signInWithCredential(credential).then((values) async {
await userAuth(credential).then((value) =>
value.addAll(output));
});
}
return output;
}
Future<Map<String, dynamic> userAuth (OAuthCredential credential) async {
Map<String, dynamic> output = {};
await auth.currentUser!.reauthenticateWithCredential(credential);
await auth.currentUser!.reload();
await auth.currentUser!.getIdTokenResult().then((result) => {
if(result.claims!.isNotEmpty){
//check your claim here
} else {
//assign log here
}
});
return output;
}
I'm facing a firebase error auth/account-exists-with-different-credential when I'm trying to sign in an already existing account(with different auth provider) with facebook. I know this question has been asked many times like here and here but all solutions works for web and I'm stuck with native plugins. I'm using Google Plus and Facebook Connect plugins to sign in on native platforms.
Code:
async continueWithGoogle() {
try {
const googleResponse = await this.googlePlus.login({ webClientId: environment.firebaseConfig.webClientId })
const googleCredential = firebase.default.auth.GoogleAuthProvider.credential(googleResponse.idToken);
const firebaseResponse = await firebase.default.auth().signInWithCredential(googleCredential);
return firebaseResponse;
} catch (error) {
console.log('continue with google: ', error);
}
}
async continueWithFacebook() {
try {
const fbResponse = await this.facebook.login(['email']);
const fbCredential = firebase.default.auth.FacebookAuthProvider.credential(fbResponse.authResponse.accessToken);
const firebaseResponse = await firebase.default.auth().signInWithCredential(fbCredential);
return firebaseResponse;
} catch (error) {
if (error.code === 'auth/account-exists-with-different-credential') {
// What should I do here?
}
console.log('continue with fb: ', error);
}
}
Can I solve this error without using any web method like signInWithRedirect() or signInWithPopup()?
I've been struggling with a weird error. Can't create a doc in firebase. There are no security rules to speak of, just:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write;
}
}
}
Firestore is initialised the normal way and is active:
import { Firebase } from "../db";
let firebase = Firebase();
let firestore = firebase.firestore();
But nothing happens after this is run other than printing "here1", the other consoles aren't doing anything and the userid doc is not being created and no collection and doc under it.
export const addEnquiry = async (data) => {
let user = await firebase.auth().currentUser;
data.uid = user.uid;
console.log("here1");
const enquiry = await firestore.collection("users").doc(data.uid).collection("enquiries").doc();
return await enquiry
.set(data)
.then((doc) => {
console.log("here2");
return true;
})
.catch((err) => {
console.log("here3");
console.log(err);
return false;
});
};
The above doesn't print anything other than "here1" and gets stuck on the setting of the doc. The doc isn't created in Firestore either.
Any idea what might be wrong and how to debug it? Wasted a good 4 hours on trying to figure it out and worried if Firestore is so buggy that it's unsafe to use it in production.
First of all, I assure you Firebase is not buggy at all, we have it running on several production applications and they're running fantastic.
Second, I think your issue here is that you're passing a function as the second argument in the set() method, which is nowhere that I can find in the API reference. Instead, it returns a promise. Your code should look like this:
firebase.firestore()
.collection("users")
.doc(uid)
.set({ uid: uid })
.then((doc) => { console.log(doc.id) })
.catch((err) => { console.log(err) })
Cheers.
Here is an example which will work for you:
file test.mjs
import { Firestore } from '#google-cloud/firestore';
const firestore = new Firestore()
export default (uid) => firestore.collection("users")
.doc(uid)
.set({ uid })
.then(() => console.log('success')) // documentReference.set() returns: Promise < void >
.catch(err => console.error(err))
It's super weird, but what solved the issue for me is adding an unnecessary doc.get() like so:
export const addEnquiry = async (data) => {
let user = await firebase.auth().currentUser;
data.uid = user.uid;
console.log("here1");
const enquiry = await firestore.collection("users").doc(data.uid).collection("enquiries").doc();
const x = await firestore.collection("users").doc(data.uid).get();
// ^^^ added the above line I don't actually need, but somehow it
// establishes a connection to firebase or something which allows the
// promise below to resolve, rather than just hang!
// Doesn't resolve without it for whatever reason!
return await enquiry
.set(data)
.then((doc) => {
console.log("here2");
return true;
})
.catch((err) => {
console.log("here3");
console.log(err);
return false;
});
};
When removing the line, the function hangs again. So have to keep it in for now!
A bit worrying that we have to use such workaround hacks to make a simple write to the firestore, to work, Firebase!
Nonetheless, hope it helps someone facing this undebuggable problem.
I have a function that triggers on firebase database onWrite. The function body use two google cloud apis (DNS and Storage).
While the function is running and working as expected (mostly), the issue is that the Socket hang up more often than I'd like. (50%~ of times)
My questions are:
Is it similar to what the rest of the testers have experienced? Is it a well known issue that is outstanding or expected behavior?
the example code is as follows:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {credentials} = functions.config().auth;
credentials.private_key = credentials.private_key.replace(/\\n/g, '\n');
const config = Object.assign({}, functions.config().firebase, {credentials});
admin.initializeApp(config);
const gcs = require('#google-cloud/storage')({credentials});
const dns = require('#google-cloud/dns')({credentials});
const zoneName = 'applambda';
const zone = dns.zone(zoneName);
exports.createDeleteDNSAndStorage = functions.database.ref('/apps/{uid}/{appid}/name')
.onWrite(event => {
// Only edit data when it is first created.
const {uid, appid} = event.params;
const name = event.data.val();
const dbRef = admin.database().ref(`/apps/${uid}/${appid}`);
if (event.data.previous.exists()) {
console.log(`already exists ${uid}/${appid}`);
return;
}
// Exit when the data is deleted.
if (!event.data.exists()) {
console.log(`data is being deleted ${uid}/${appid}`);
return;
}
const url = `${name}.${zoneName}.com`;
console.log(`data: ${uid}/${appid}/${name}\nsetting up: ${url}`);
setupDNS({url, dbRef});
setupStorage({url, dbRef});
return;
});
function setupDNS({url, dbRef}) {
// Create an NS record.
let cnameRecord = zone.record('cname', {
name: `${url}.`,
data: 'c.storage.googleapis.com.',
ttl: 3000
});
zone.addRecords(cnameRecord).then(function() {
console.log(`done setting up zonerecord for ${url}`);
dbRef.update({dns: url}).then(res => console.log(res)).catch(err => console.log(err));
}).catch(function(err) {
console.error(`error setting up zonerecord for ${url}`);
console.error(err);
});
}
function setupStorage({url, dbRef}) {
console.log(`setting up storage bucket for ${url}`);
gcs.createBucket(url, {
website: {
mainPageSuffix: `https://${url}`,
notFoundPage: `https://${url}/404.html`
}
}).then(function(res) {
let bucket = res[0];
console.log(`created bucket ${url}, setting it as public`);
dbRef.update({storage: url}).then(function() {
console.log(`done setting up bucket for ${url}`);
}).catch(function(err) {
console.error(`db update for storage failed ${url}`);
console.error(err);
});
bucket.makePublic().then(function() {
console.log(`bucket set as public for ${url}`);
}).catch(function(err) {
console.error(`setting public for storage failed ${url}`);
console.error(err);
});
}).catch(function(err) {
console.error(`creating bucket failed ${url}`);
console.error(err);
});
}
I'm thinking your function needs to return a promise so that all the other async work has time to complete before the function shuts down. As it's shown now, your functions simply returns immediately without waiting for the work to complete.
I don't know the cloud APIs you're using very well, but I'd guess that you should make your setupDns() and setupStorage() return the promises from the async work that they're doing, then return Promise.all() passing those two promises to let Cloud Functions know it should wait until all that work is complete before cleaning up the container that's running the function.