Firebase cloud functions: is `createId()` available on the server side? - firebase

If I want to write to the database from my client side, I can inject an AngularFirestore instance and generate an id automatically using createId():
const individualId = this.angularFirestore.createId();
But if I want to do the same thing in a cloud function, using the Firestore admin API, I can't find an equivalent operation. I can create a Firestore instance in a cloud function by running
const db = admin.firestore();
However, the object that is created has no createId() function available.
Is there an equivalent to createId() that I can use within a cloud function?

I understand from this issue and this article that "AngularFirestore.createId() generates a new id from a symbolic collection named '_'".
If you want to mimic this behaviour in a Cloud Function, you could use the doc() method of a CollectionReference without specifying any path. You will get a DocumentReference, and then you can use the id property to get the "last path element of the referenced document".
Something like the following:
const db = admin.firestore();
const docRef = db.collection('_').doc();
const newId = docRef.id;
Note that, as explained in the issue referred to above, it is a bit weird to "use a generic collection instead of an actual collection" to generate an id, because you would normally use the collection in which you want to create a new Document. But this is not a problem, according to this comment from James Daniels (who is a Firebaser), since the Firestore auto-generated ID is "just a random string and doesn't take the path into consideration at all".

in JavaScript, for the new Firebase 9 (January 2022). In my case I am developing a comments section:
const commentsReference = await collection(database, 'yourCollection');
await addDoc(commentsReference, {
...comment,
id: doc(commentsReference).id,
date: firebase.firestore.Timestamp.fromDate(new Date())
});
Wrapping the collection reference (commentsReference) with the doc() provides an identifier (id)

Related

How do I add a document reference with an auto generated ID when writing a batch in Firebase?

When doing normal transactions in Firebase you can just use the .add function to add a new document with an auto generated ID; however, when doing a batch write with Web version 9 of the API I cannot find any documentation on how to add a new document with a auto generated ID. Currently I have the following code which is not working:
let ref = doc(db, "projects", doc())
batch.add(ref, element);
await batch.commit();
This throws the error "Function doc() cannot be called with an empty path.". In Web version 8 this worked apparently by just calling .doc(). How does one accomplish this?
This is what worked for me:
let ref = doc(collection(db, "projects"))
For Node.js, or using the Firebase V8 syntax, a working solution would be:
let ref = db.collection("projects").doc()
batch.set(ref, {...data})
...
According to the Firebase documentation on adding a document:
In some cases, it can be useful to create a document reference with an auto-generated ID, then use the reference later. For this use case, you can call doc():
import { collection, doc, setDoc } from "firebase/firestore";
// Add a new document with a generated id
const newCityRef = doc(collection(db, "cities"));
// later...
await setDoc(newCityRef, data);
So it seems you'll need:
let ref = doc(db, collection("projects"))

Determine RTDB url in a trigger function

i m bulding a scalable chat app with RTDB and firestore
here is my raw structure of shards
SHARD1
Chats {
chat01: {
Info: {
// some info about this chatroom
},
Messages ...
}, ....
}
SHARD2...
now i have write triggers on all the info nodes of all the shards.
i want get the ID of the shard
How do i know what shard it actually ran on ?
[EDIT]
console.log(admin.app().name); // it prints "[DEFAULT]" in console
Puf and team please help
When a Realtime Database trigger is invoked, the second argument is an EventContext object that contains information about the database and node that was updated. That object contains a resource string, which has what you're looking for. According to the documentation for that string, it's name property will be formatted as:
projects/_/instances/<databaseInstance>/refs/<databasePath>
The databaseInstance string is what you're looking for. So, you can just split the string on "/" and take the 4th element of that array:
export const yourFunction = functions.database
.instance('yourShard')
.ref('yourNode')
.onCreate((snap, context) => {
const parts = context.resource.name.split('/')
const shard = parts[3]
console.log(shard)
})
If all you need is a reference to the location of the change, in order to perform some changes there, you can just use the ref property on the DataSnapshot that was delivered in the first argument, and build a path relative to there.

Querying Firestore documents by Array or Map fields values in Firebase console

Here, I want to query by the value "ministoreid1" in Firebase console. But I am not able to figure out. Here, I am trying to do the query in console not using codes.
I have filed the feature request at Alex' suggestion. And the reply I received from Firebase Support:
Currently, there is no query similar to array-contains available in the Firestore Console. I can file a feature request ticket on your behalf. However, I can't guarantee anything at the moment, so please watch out for any updates on our blog or release notes for now. For the map field, you can try to filter on the console using the format: 'mapFieldName.keyName' in the field text box
So we can query for map values by 'mapFieldName.keyName'. I didn't know this before.
Here, I am trying to do the query in console not using codes.
Unfortunately, there is currently no way you can filter your documents in the Firebase console according to a value that exist in an array. As you can see, there are only the following operators:
== is equal to
> is after
>= is after and includes
< is before
<= is before and includes
But an whereArrayContains option it is not present yet. I recommend you file a feature request for that. It might be also useful for other developers.
The query that you perform in the console does't return any results because you are checking if the mini_stores_assigned is equal to ministoreid1, which obviously is not since the mini_stores_assigned property is an array and not a String so you can compare them.
For future use, Firebase has added the feature request by Ssuburat. You can now can filter your documents in the Firebase console according to a value that exist in an array.
###FILTER BLOGS BY USER.
for example if you have two collections (one to many)
/users
/blogs
blog and user has these schemes:
blog: { name,date,user:{myusername:true}}
//notice that user is a map or object and document blog has id itself wich you can use in user document and viceversa.
user:{name,lastname,blogs:{idblog1:true,idblog2:true}} //blogs is a map or object
if you want to filter by map object you can do this:
import firebase from "firebase/compat/app";
import { getFirestore } from "firebase/firestore";
const appFirebase = firebase.initializeApp(firebaseConfig);
export const dbFirebase = getFirestore(appFirebase);
const myuser= "myusername"
const q = query(collection(dbFirebase, "blogs"), where(`user.${myuser}`, "==", true));
const blogsSnapshot = await getDocs(q);
blogsSnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
console.log({blogsSnapshot});

How to add 2 collections in Firestore using React Native?

I want to add 2 collections in Firestore in React Native.
Like JOIN can be used to add 2 tables. Is there any alternative for JOIN in Firestore to add collections?
I want to add these 2 collections users and users_2
How can I do this? Please help
At the time of writing it is not possible to query documents across collections in Firestore (it is apparently a feature that is on the roadmap however, see this recent blog post https://cloud.google.com/blog/products/databases/announcing-cloud-firestore-general-availability-and-updates -see bullet point "More features coming soon"-).
So that means that you'll have to issue two queries (one for each table, to get all the collection docs) and join/combine their results in your front end.
Another approach would be to duplicate your data (which is quite common in NoSQL world) and create a third collection that contains copies of all the documents.
For this last approach you could use a Batched Write as follows (in Javascript):
// Get a new write batch
var batch = db.batch();
var docData = {email: 'test#gmail.com', fullname: 'John Doe'}
// Set the value of doc in users collection
var usersRef = db.collection('users').doc();
batch.set(usersRef, docData);
// Set the value of doc in the allUsers collection (i.e. the third collection)
var allUsersRef = db.collection('allUsers').doc();
batch.set(allUsersRef, docData);
// Commit the batch
return batch.commit().then(function () {
// ...
});

how do I get the dataID when using cloud firestore triggers function?

I have an Event Collection in the Firestore database like this:
I want to use cloud firestore triggers. when a user attends an event, the capacity of the event will be -1, and when this field is updated I want to automatically update another field ("rankPoint") +3
to implement this, I need to Trigger a function when a document is updated
from firestore documentation, it will be like this
exports.updateUser = functions.firestore
.document('users/{userId}')
.onUpdate((change, context) => {
// Get an object representing the document
// e.g. {'name': 'Marie', 'age': 66}
const newValue = change.after.data();
// ...or the previous value before this update
const previousValue = change.before.data();
// access a particular field as you would any JS property
const name = newValue.name;
// perform desired operations ...
});
for my case, it should be 'events/{eventId}' right? but how do I get that eventID in the wildcard? does it come from client side? I mean in iOS/Android I will write the code to update like
db.collection("eventss").document("someEventIDHere").setData(data)
is it from the client?
Your function will only be delivered the document that matched your function's pattern (users/{userId}) that was changed. Other documents are not available until you query for them. So, if you want a document from you events collection, you will have to write some code to access it, then decide what to do from there.
It sounds like you're expecting there to be an eventId wildcard, but there is not. There is just the userId wildcard that you defined in your function. Other values will need to be derived from the data you have available in your user document.

Resources