I'm trying to update list in document but it replace all data with the new ,, I only want to add items without delete old list data
this my code:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.setUsername = functions.https.onCall((data, context) => {
const documentRef = admin.firestore().collection('userInfo').doc(data);
return documentRef.get()
.then((doc) => {
if (doc.exists) {
return documentRef.update({'list': ['item3']});// here update
} else {
return { result: "Doc not found!" };
}
})
.catch(err => {
console.log("Error: ", err)
});
});
Related
I am trying to send a list of arrays to Firestore using a variable called array_list but when I check my firebase console the array is present but the value inside of it is empty.
let array_list = [];
let user_id = localStorage.getItem("userId");
function add_data() {
let i = 0;
for(i;i<10;i++){
array_list.push(i);
}
}
add_data()
let db = firebase.firestore();
if (user_id !== null) {
var doc = db.collection("users").doc(user_id);
}
const sendHistData = () => {
console.log("Creating Database...");
doc
.set({
browsingHistory: array_list,
})
.then(() => {
console.log("Document successfully written!");
})
.catch((error) => {
console.log(error);
});
};
if(user_id!==null){
add_data();
sendHistData();
}
Here is the link to the full code
Here is the screenshot
The var "doc" seems to be undefined in your sendHistData function. Try refactoring the function:
let db = firebase.firestore();
const sendHistData = () => {
// if (!user_id) return null // user not logged in
const db = firebase.firestore().collection("users").doc(user_id)
console.log("Creating Database...");
doc
.set({
browsingHistory: array_list,
})
.then(() => {
console.log("Document successfully written!");
})
.catch((error) => {
console.log(error);
});
};
Also you are checking if user_id is null or not before calling the function so verifying that again inside of the function is redundant.
I'm working on a React app, which connects to a firebase database. Part of the app reads in a list of Items belonging to the current User, and then reads a config object in for each one, and finally updates the items in state. I'm having trouble getting it to work - I seem to keep getting
My component is:
const Dashboard = () => {
const authUser = useContext(AuthUserContext);
const firebase = useContext(FirebaseContext);
const [error, setError] = useState<string|null>(null);
const [firebaseToken, setFirebaseToken] = useState<string|null>(null);
const [items, setItems] = useState<Array<ItemModel>>([]);
// On first render, get all Items
useEffect(() => {
if(!authUser) return;
if(!firebase) return;
let userId = authUser.id;
const getItems = () => {
firebase.doGetIdToken()
.then((token) => {
// Save token so it can be passed down
setFirebaseToken(token);
url = "items/" + userId;
Client.getData(url, token)
.then((itemResults:Array<ItemModel>) => {
// Get config for each Item
// Set up an empty array to hold the new data
const itemResultsWithConfigs:Array<ItemModel> = []
// Now get the config for each item
itemResults.forEach((item:ItemModel) => {
// Get config for this Item
url = "/items/config/" + item.id;
Client.getData(url, token)
.then((newConfig:ConfigModel) => {
let newItem:ItemModel = {
...item,
config: newConfig
}
// Add full item to list & update list
itemResultsWithConfigs.push(newItem);
})
})
setItems(itemResultsWithConfigs);
})
});
})
})
.catch(() => setError("Unable to connect to database"))
}
getItems();
}, [authUser, firebase])
return (
<>
<ul>
{
items.map((item:ItemModel) => {
return <li key={item.id}>{item.name}</li>
})
}
</ul>
</>
);
}
export default Dashboard;
Client.getData is:
async function getData(path:string, token:string) {
const object:AxiosRequestConfig = {
...obj,
method: 'GET',
headers: {
...obj.headers,
'Authorization': `Bearer ${token}`,
},
};
try {
const response:AxiosResponse = await axios.get(`${baseUrl}${path}`, object);
checkStatus(response);
const parsedResult = parseJSON(response);
return parsedResult;
} catch (error) {
throw error;
}
}
The problem is that the async function (getData) is returning at different times, therefore the array of items is being overwritten some of the time. Currently this is only rendering one or two of the items instead of the 3 that I know should be there.
How do I approach this?
Since itemResultsWithConfig is derived asynchronously, a good idea is to map and wait for all the promises to resolve using Promise.all
const getItems = () => {
firebase.doGetIdToken()
.then((token) => {
// Save token so it can be passed down
setFirebaseToken(token);
url = "items/" + userId;
Client.getData(url, token)
.then((itemResults:Array<ItemModel>) => {
// Get config for each Item
// Set up an empty array to hold the new data
// Now get the config for each item
let promises = itemResults.map((item:ItemModel) => {
// Get config for this Item
url = "/items/config/" + item.id;
return Client.getData(url, token)
.then((newConfig:ConfigModel) => {
let newItem:ItemModel = {
...item,
config: newConfig
}
return newItem;
})
})
Promise.all(promises).then((itemResultsWithConfigs:Array<ItemModel>) => setItems(itemResultsWithConfigs))
})
});
})
I have an app that takes in an object named user. The user object has userId information which is needed to get information from firestore database if the person is a paid member or not, membership is either true or false. If the person is a non-paid member than i want to display a button, and if he is a paid member, than i want the button to not be displayed. The problem i am having is how to return a boolean from the PaidMembership() function?
const App = ({ user, database }) => {
const PaidMembership = () => {
var test = null;
docRef.get().then(function(doc) {
if (doc.exists) {
test = doc.data().membership;
//console.log(paidMembership);
} else {
console.log("Error: no such document exists")
test = false;
}
})
return test;
}
return (
{ PaidMembership() ? render : dont render}
)
}
Make test variable inside state and check
const [test, setTest] = useState(null);
const App = ({ user, database }) => {
const PaidMembership = () => {
docRef.get().then(function(doc) {
if (doc.exists) {
setTest( doc.data().membership);
//console.log(paidMembership);
} else {
console.log("Error: no such document exists")
setTest(null);
}
})
return test;
}
return (
{ test ? "" : <button>show button</button>}
)
}
This is because docRef.get returns promise and you are treating it as a normal function call. Try using this :
const App = async ({ user, database }) => {
const PaidMembership = async () => {
const doc = await docRef.get();
return doc.exists;
};
return (await PaidMembership()) ? "render" : "dont render";
};
currently I am working on a app but struggling to find since last two weeks the following:
I have react native iOS app with RN-iap for subscription.. and would like to implement receipt verification via cloud function at firebase.
I found a similar solution but its with SWIFT: https://www.loopwerk.io/articles/2020/storekit-webhooks-firestore/
can anybody please help me convert the code (swift below) into React Native ? really appreciate
or if any suitable example or lines please.
(I am using React native firebase).
I can able to fetch receipt and save in Firestore collection. Thanks in advance.
below are the codes:
FRONT END CALLING Cloud function
import Firebase
import FirebaseFunctions
import Foundation
final class CloudFunction {
private lazy var functions = Functions.functions()
func validateReceipt(receipt: String, completionHandler: #escaping () -> Void) {
let parameters = ["receipt": receipt]
functions.httpsCallable("validateReceipt").call(parameters) { _, error in
if let error = error {
print(error)
}
completionHandler()
}
}
}
Cloud Function for above:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const fetch = require('node-fetch');
const db = admin.firestore();
const runtimeOpts = {
memory: '1GB',
};
function validateAndStoreReceipt(url, options, userSnapshot) {
return fetch(url, options).then(result => {
return result.json();
}).then(data => {
if (data.status === 21007) {
// Retry with sandbox URL
return validateAndStoreReceipt('https://sandbox.itunes.apple.com/verifyReceipt', options, userSnapshot);
}
// Process the result
if (data.status !== 0) {
return false;
}
const latestReceiptInfo = data.latest_receipt_info[0];
const expireDate = +latestReceiptInfo.expires_date_ms;
const isSubscribed = expireDate > Date.now();
const status = {
isSubscribed: isSubscribed,
expireDate: expireDate,
};
const appleSubscription = {
receipt: data.latest_receipt,
productId: latestReceiptInfo.product_id,
originalTransactionId: latestReceiptInfo.original_transaction_id
};
// Update the user document!
return userSnapshot.ref.update({status: status, appleSubscription: appleSubscription});
});
}
exports.validateReceipt = functions.runWith(runtimeOpts).https.onCall(async (data, context) => {
if (!context.auth) {
throw new functions.https.HttpsError('permission-denied', 'The function must be called while authenticated.');
}
if (!data.receipt) {
throw new functions.https.HttpsError('permission-denied', 'receipt is required');
}
// First we fetch the user
const userSnapshot = await db.collection('users').doc(context.auth.uid).get();
if (!userSnapshot.exists) {
throw new functions.https.HttpsError('not-found', 'No user document found.');
}
// Now we fetch the receipt from Apple
let body = {
'receipt-data': data.receipt,
'password': 'MY_SECRET_PASSWORD',
'exclude-old-transactions': true
};
const options = {
method: 'post',
body: JSON.stringify(body),
headers: {'Content-Type': 'application/json'},
};
return validateAndStoreReceipt('https://buy.itunes.apple.com/verifyReceipt', options, userSnapshot);
});
continuation another cloud function:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const db = admin.firestore();
const runtimeOpts = {
memory: '1GB',
};
exports.appleWebhook = functions.runWith(runtimeOpts).https.onRequest(async (req, res) => {
// Only allow POST requests
if (req.method !== 'POST') {
return res.status(403).send('Forbidden');
}
// Check for correct password
if (req.body.password !== 'MY_SECRET_PASSWORD') {
return res.status(403).send('Forbidden');
}
const receipt = req.body.unified_receipt.latest_receipt_info[0];
// Find the user with this stored transaction id
const userQuerySnapshot = await db.collection('users')
.where('appleSubscription.originalTransactionId', '==', receipt.original_transaction_id)
.limit(1)
.get();
if (userQuerySnapshot.empty) {
throw new functions.https.HttpsError('not-found', 'No user found');
}
const expireDate = +receipt.expires_date_ms;
const isSubscribed = expireDate > Date.now();
const status = {
isSubscribed: isSubscribed,
expireDate: expireDate,
};
const appleSubscription = {
receipt: req.body.unified_receipt.latest_receipt,
productId: receipt.product_id,
originalTransactionId: receipt.original_transaction_id,
};
// Update the user
return userQuerySnapshot.docs[0].ref.update({ status: status, appleSubscription: appleSubscription }).then(function() {
return res.sendStatus(200);
});
});
I'm trying to delete a doc from Firestore, I don't get an error but the document is still in the database: simply as that, it keeps on being in the collection it belongs to.
The cloud function is:
exports.countdowns_crud = functions.https.onRequest((request, response) => {
var req = request;
var res = response;
if (request.method === 'DELETE') {
const countdownId = request.path.split('/')[1];
const deleteOperation = db.DeleteCountdown(countdownId);
if (!deleteOperation) {
console.log('Delete operation result: ', deleteOperation);
cors(req, res, () => {
res.status(204).send("DELETED");
});
}
else {
console.error(addOperation);
cors(req, res, () => {
res.status(500).send("INTERNAL SERVER ERROR");
});
};
return;
}
cors(req, res, () => {
res.status(405).send("NOT ALLOWED");
return;
});
})
The DeleteCountdown function is in another module:
module.exports = {
DeleteCountdown: (countdownId) => {
const countdownsCollection = app.firestore.collection('countdowns');
countdownsCollection.doc(countdownId).delete()
.then((res) => {
console.log('Result: ', res);
return null;
})
.catch((e) => {
console.error(`unable to delete the countdown ${countdowmnId}: ${e}`);
return e;
});
}
}
This is the logic in a google cloud function, which it's correctly invoked by my react app upon deletion. The passed id is correct, no error is returned, but the doc keeps on living in the collection.
I had the same problem, no error and null returned (exactly the same when it works) because I forgot to set the rules to allow writes (or specifically deletions) directly in the Firebase console or by the firestore.rules files