My Firestore sub collection names are of the format 'subcollection_name_yyyymmdd'. Whenever new documents are added, they are identified through the 'yyyymmdd' part of the subcollection name. I need to take Firestore exports for these subcollections incrementally on the 'yyyymmdd' values. Below is my cloud function taking full firestore export at the moment. Is there a way I can parameterize the 'collectionIds:' to take the subcollection names by passing the yyyymmdd part as a variable/parameter?
eg: something like collectionIds: ['subcollection_name_{$date}']?
const firestore = require('#google-cloud/firestore');
const client = new firestore.v1.FirestoreAdminClient();
const bucket = 'gs://BUCKET_NAME'
exports.scheduledFirestoreBackup = (event, context) => {
const databaseName = client.databasePath(
// process.env.GCLOUD_PROJECT,
"PROJECT_ID",
'(default)'
);
return client
.exportDocuments({
name: databaseName,
outputUriPrefix: bucket,
collectionIds: ['subcollection_name'],
})
.then(responses => {
const response = responses[0];
console.log(`Operation Name: ${response['name']}`);
return response;
})
.catch(err => {
console.error(err);
});
};
Related
ERROR
ERROR TypeError: (0, _database.where) is not a function. (In '(0, _database.where)('email', '==', email)', '(0, _database.where)' is undefined)
In here I am generating a uniqe perant in the database using uid and update some values in it, I am trying to do some filitration based on the email to know if users exist then update the values if not then generate a new user
import { ref, get, set, query, where} from 'firebase/database';
useEffect(() => {
const writeToDatabase = () => {
if (location && location.coords && UserDataFromGoogleAuth) {
const usersRef = ref(database, 'users');
const email = UserDataFromGoogleAuth.email;
if (email) {
const query = query(usersRef, where('email', '==', email));
get(query).then((snapshot) => {
const uuid = snapshot.exists() ? Object.keys(snapshot.val())[0] : uid();
const userRef = ref(database, `/users/${uuid}`);
const userData = {
id: uuid,
name: UserDataFromGoogleAuth.displayName,
email: email,
includedKids: 0,
isSubscribed: false,
long: location.coords.longitude,
lat: location.coords.latitude,
online: props.online,
profilePicture: UserDataFromGoogleAuth.photoURL,
};
set(userRef, userData);
}).catch(error => {
console.log(error);
});
}
}
};
writeToDatabase();
}, [UserDataFromGoogleAuth, location, props.online]);
database structure:
Database> users> {uid foreach user}> {email}
The where method is part of the Cloud Firestore API (firebase/firestore).
There is no direct equivalent in the Realtime Database API (firebase/database) that allows using a similar shorthand.
Instead, you invoke one of the many QueryConstraint returning methods:
endAt(), endBefore(), startAt(), startAfter(), limitToFirst(), limitToLast(), orderByChild(), orderByChild(), orderByKey(), orderByPriority(), orderByValue() or equalTo(). Take a look at QueryConstraint for links to the API reference for these methods and read over the documentation for Realtime Database: Sorting and filtering data.
The equivalent of
// firestore
const query = query(usersColRef, where('email', '==', email));
is
// database
const query = query(usersRef, orderByChild('email'), equalTo(email));
I am building a social media app (very simple) an I want to store user's activity in firestore database. I have a collection of "users" and I keep user's id, user's username, user's profile pic there. But I dont think that user's activity should be stored there as well (correct me if I am wrong?)
So I created a new collection called UserActivity where I store user's activity. I wanted to store if a user has been searching on a profile so I do the following:
const logUserSearch = async (term) => {
await firebase
.firestore()
.collection("userActivity")
.doc(firebase.auth().currentUser.uid)
.collection("userSearch")
.add({
term: term,
date: firebase.firestore.FieldValue.serverTimestamp(),
})
};
I think the above query solves the problem with user's search term's. However I want to store if a user has visited a profile. So here is my question: what is the correct way to store if a user visited a profile? Should I add new subcollection "profileVisit", something like that:
const logProfileVisit = async (searchTerm, profileId) => {
await firebase
.firestore()
.collection("userActivity")
.doc(firebase.auth().currentUser.uid)
.collection("profileVisit")
.doc(profileId)
.add({
source: searchTerm,
date: firebase.firestore.FieldValue.serverTimestamp(),
})
};
But then how do I calculate which are the most "popular" profiles? Should I create my database in another way, like this:
const logProfileVisit = async (searchTerm, profileId) => {
await firebase
.firestore()
.collection("userActivity")
.doc(profileId)
.collection("profileVisit")
.add({
user: firebase.auth().currentUser.uid
source: searchTerm,
date: firebase.firestore.FieldValue.serverTimestamp(),
})
};
So that I can easily calculate which are the most "popular" profiles? What about the user case where I need to calculate "top 10 fan profiles" or something similar? I.e. How do I calculate who visited your profile most often?
A root level collection "userActivity" (or a sub-collection) should be enough. You can store the activity type as a field instead of sub-collections as shown below:
users -> {userId} -> userActivity -> {logId}
(col) (doc) (col) (doc)
But then how do I calculate which are the most "popular" profiles?
You can store a number field in that profile's document and whenever the logProfileVisit is called, increment that:
const usersCol = firebase.firestore().collection("users")
const logProfileVisit = async (searchTerm, profileId) => {
await Promise.all([
usersCol
.doc(currentUserId)
.collection("userActivity")
.add({
source: searchTerm,
date: firebase.firestore.FieldValue.serverTimestamp(),
type: "profileVisit"
}),
usersCol
.doc(profileUserId)
.update({
profileViews: firebase.firestore.FieldValue.increment(1),
})
])
};
You can also use batch writes while updating these fields so either both the operations fail or pass.
You can also use firestore -> audit logs -> pub/sub sink -> cloud function -> firestore.
I explain it a little more at https://justin.poehnelt.com/posts/tracking-firestore-user-activity/. Below is the function that listens to the Pub/Sub sink and writes back to Firestore.
import * as firebaseAdmin from "firebase-admin";
import * as functions from "firebase-functions";
export default functions.pubsub
.topic("firestore-activity")
.onPublish(async (message) => {
const { data } = message;
const { timestamp, protoPayload } = JSON.parse(
Buffer.from(data, "base64").toString()
);
const uid =
protoPayload.authenticationInfo.thirdPartyPrincipal.payload.user_id;
const writes = protoPayload.request.writes;
const activityRef = firebaseAdmin
.firestore()
.collection("users")
.doc(uid)
.collection("activity");
await Promise.all(
// eslint-disable-next-line #typescript-eslint/no-explicit-any
writes.map((write: any) => {
activityRef.add({ write, timestamp });
})
);
});
I then have a collection that looks like the following.
I would like to retrieve the subcollections by making my request with geofirestore, like so:
The id of each PRODUCTS corresponds to that of the user who created new products (for the moment there is only one).
That's my code right now:
import firestore from '#react-native-firebase/firestore';
import * as geofirestore from 'geofirestore';
const firestoreApp = firestore();
const GeoFirestore = geofirestore.initializeApp(firestoreApp);
const geocollection = GeoFirestore.collection('PRODUCTS');
const query = geocollection.limit(30).near({
center: new firestore.GeoPoint(coords.latitude, coords.longitude),
radius: 1000,
});
try {
query.onSnapshot((querySnapshot) => {
const productsQueried = querySnapshot.docs.reduce(
(result, documentSnapshot) => {
console.log(documentSnapshot);
if (documentSnapshot.id !== user.uid) {
result.push(documentSnapshot.data());
}
return result;
},
[]
);
setListOfProducts(productsQueried);
console.log(productsQueried);
setLoading(false);
});
} catch (error) {
console.log(error);
}
Of course, I can only find the geocollection, but cannot access the 'USER_PRODUCTS' collection inside.
{exists: true, id: "OUJ6r3aF9nVfgtfkQRES7kpYCko1", distance: 0, data: ƒ}
The final goal is to retrieve a list of products for each close customer and then sort so as not to retrieve that of the current user.
Do I necessarily have to make a second request (can I do it in one?) Or do I have to change the way I save the product lists of different users in firestore?
Hope you're in good health.
I have a problem.
export function fetchListing() {
return function (dispatch) {
dispatch(fetchListingRequest());
//Getting Listing where status is in_review
firebase
.firestore()
.collection("listings")
.where("status", "==", "in_review")
.onSnapshot(
snapshot => {
const data = [];
snapshot.docs.forEach(doc => {
const temp = {};
// Getting address of business
firebase
.firestore()
.collection("users")
.doc(doc.data().business_id)
.get()
.then(users => {
temp["address"] = users.data().address;
})
.catch(error => {
dispatch(fetchListingFailed(error));
});
temp["title"] = doc.data().title;
temp["description"] = doc.data().description;
temp["listing_file"] = doc.data().listing_file;
data.push([doc.id, temp]);
});
dispatch(fetchListingSucess(data));
},
error => {
dispatch(fetchListingFailed(error));
}
);
};
}
I am Unable to get address in state but when I log it It displayed in console. I am able to access address when I am retrieving it from firebase and also in reducer I am also getting address.
reasons can be :
The hierarchy of your firestore collection
or you have to know that in js you can't affect the data to a variable that is in the main prog just when it is in a one level functions
for exemple here you can do this
locale = this ;
than you can use all the variables in two other levels
I want to get data from my database on fire base and want to save that data to amount amount: snapshot, I did apply this const snapshot = firestore.collection('payment').doc(context.params.amount).get(); does that works in the same way? but I am getting an error that context is undefined.
I actually want to get data from database.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const firestore= admin.firestore();
const stripe = require('stripe')('');
const snapshot = firestore.collection('payment').doc(context.params.amount).get();
const customer = stripe.customers.create({
email: 'customer#example1.com',
});
stripe.customers
.create({
email: 'foo-customer#example.com',
})
.then((customer) => {
return stripe.customers.createSource(customer.id, {
source: 'tok_visa',
});
})
.then((source) => {
return stripe.charges.create({
amount: snapshot,
currency: 'usd',
customer: source.customer,
});
})
.then((charge) => {
// New charge created on a new customer
})
.catch((err) => {
// Deal with an error
});
you are trying to get amount through accessing params through context,
depends on your error, this means context is undefined which means you are trying to get params of undefined. you need to explain what is context means here, is it a global variable? is this code inside a cloud function? if yes you need to move this declaration const snapshot = firestore.collection('payment').doc(context.params.amount).get();
inside your cloud function ,
this is an example of firebase cloud function