Can I change the name of a document in Firestore? - google-cloud-firestore

I'm currently working on an app where I have to retrieve data from Google's Firestore.
My data structure looks like this:
users
- name#xxx.com
- more data
Is there a way for me to change the name#xxx.com to just name?
I can't see a method to change the name of a document.

I think the best way to do this is to get the data from 'name#xxx.com' and upload it to a new document called 'name' and then delete the old one.
Just as an example:
const firestore = firebase.firestore();
// get the data from 'name#xxx.com'
firestore.collection("users").doc("name#xxx.com").get().then(function (doc) {
if (doc && doc.exists) {
var data = doc.data();
// saves the data to 'name'
firestore.collection("users").doc("name").set(data).then({
// deletes the old document
firestore.collection("users").doc("name#xxx.com").delete();
});
}
});

There might be a case when u realize that you should have used autogenerated IDs for all your firebase documents in a collection and now you want to change the document IDs in your Collection ("collection_name") and also want to store their previous IDs as a new field ("prevID") in the new document then here's what you can do:-
FirebaseFirestore firebaseDb;
ArrayList<Map<String,Object>> data = new ArrayList<>();
firebaseDB.collection("collection_name").get.addOnSuccessListener(
queryDocumentSnapshots -> {
for (DocumentSnapshot d : queryDocumentSnapshots) {
Map<String,Object> map = d.getData();
map.put("prevID", d.getId());
data.add(map);
}
for(Map<String, Object> d : data){
Task<DocumentReference> dd = firebaseDb.collection("collection_name").add(d);
dd.addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
#Override
public void onSuccess(DocumentReference documentReference) {
firebaseDb.collection("collection_name").document((String) d.get("prevID")).delete();
}
});
}
});

Related

Adding map in Firestore?

How can I append a new Map type in firestore?
void addUser() async {
final us = _firestore.collection("users").doc(_search.text);
us.update({
"requests": (
{_auth.currentUser?.email: rep}
),
});
}
Am using this method but the requests field in my firestore overwrites the previous one I want it to be appended. Any idea?
The update() method will always overwrite your previous field with the new one, so achieving this with one operation using the update() is not possible, however, you can always get the current field from the document, then update its value, then save it again in the document like this:
void addUser() async {
final us = _firestore.collection("users").doc(_search.text);
final currentDoc = await us.get(); // we get the document snapshot
final docDataWhichWeWillChange = currentDoc.data() as Map<String, dynamic>; // we get the data of that document
docDataWhichWeWillChange{"requests"]![_auth.currentUser?.email] = rep; // we append the new value with it's key
await us.update({
"requests": docDataWhichWeWillChange["requests"],
}); // then we update it again
}
But you should use this after being aware that this method will make two operations in your database, a get() and update().
If you want to record multiple values, an array is an appropriate type. So, you could use the .arrayUnion method to record multiple entries.
final washingtonRef = db.collection("cities").doc("DC");
// Atomically add a new region to the "regions" array field.
washingtonRef.update({
"regions": FieldValue.arrayUnion(["greater_virginia"]),
});

How to retrive all the documents of firestore at once using flutter?

I am building an Appointment Booking application want to retrieve all my documents from firestore at once on a button click. I used this:
Future<void> userAppointmentHistory() async {
String collectionName =
FirebaseAuth.instance.currentUser?.displayName as String;
String doc_id = "YyWqd9VlB1IdmYoIIFTq";
await FirebaseFirestore.instance
.collection(collectionName)
.doc(doc_id)
.snapshots()
.listen(
(event) {
print(
event.get("selectedDate"),
);
},
);
}
From the above code, I am getting only the specified document id details. So please help me modify the above code so that I get all the document details as I want to display these details on cards as my booked appointment history.
Here you are passing the doc id String doc_id = "YyWqd9VlB1IdmYoIIFTq";
You don't want to pass that if you want the full documents.
just pass the collection reference.
Follow the below code
fetchData() {
CollectionReference collectionReference =
FirebaseFirestore.instance.collection(collectionName);
collectionReference.snapshots().listen((snapshot) {
setState(() {
document = snapshot.docs;
});
print(document.toString);
});
}
Rudransh Singh Mahra,
It's as easy as putting text widget in our application.
Solution
You did it in right way but by mistake you have passed a specific id of documents in doc() as doc('YyWqd9VlB1IdmYoIIFTq'). you just need to remove that id from there and you may get your desired output.
What actually happens :
In your query you pass specific docId. So that it will returns that specified id document from your collection. To get all the documents from that collection you just need to do as follows,
Future<void> userAppointmentHistory() async {
String collectionName =
FirebaseAuth.instance.currentUser?.displayName as String;
// String doc_id = "YyWqd9VlB1IdmYoIIFTq";
await FirebaseFirestore.instance.collection(collectionName).doc().get()
}
And you will get your desired output if collectionName is valid and exist in firestorm database.

How can I set up a Stream for a subcollection in Firestore?

I have a Firestore database with the following structure:
usersCollection => user1 => productsHeldCollection => product1, product2, ...
I can set up a Stream for the userCollection, but am struggling to set one up for the productsHeldCollection which is a subcollection for each user. This is what I have tried.
First I created a reference for the subcollection:
final CollectionReference productsHeldCollection = Firestore.instance.collection('users').document().collection('productsHeld');
But I am not sure what to pass into the document() as I want it to be whatever the current user id is.
I then did the following:
List<ProductHeld> _productsHeldListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.documents.map((doc) {
return ProductHeld(
productName: doc.data['Product Name'],
purchaseDate: doc.data['Purchase Date'],
expiryDate: doc.data['Expiry Date'], // these are fields within the subcollection
);
}).toList();
}
// Stream of products
Stream<List<ProductHeld>> get products {
return productsHeldCollection.snapshots().map(_productsHeldListFromSnapshot);
}
The names of documents within a collection are unique. You can provide your own keys, such as user IDs, or you can let Cloud Firestore create random IDs for you automatically.
The parameter you pass into the document() is the name of the document.
Google public documentation provides more details on how to design your hierarchical data structures to work in Cloud Firestore.

Firestore - batch.add is not a function

The documentation for Firestore batch writes lists only set(), update() and delete() as permitted operations.
Is there no way to add an add() operation to the batch? I need a document to be created with an auto-generated id.
You can do this in two steps:
// Create a ref with auto-generated ID
var newCityRef = db.collection('cities').doc();
// ...
// Add it in the batch
batch.set(newCityRef, { name: 'New York City' });
// Commit at the end
await batch.commit();
The .doc() method does not write anything to the network or disk, it just makes a reference with an auto-generated ID you can use later.
In my case, using AngularFire2, I had to use the batch.set() method, passing as first parameter the document reference with an ID previously created, and the reference attribute:
import { AngularFirestore } from '#angular/fire/firestore';
...
private afs: AngularFirestore
...
batch.set(
this.afs.collection('estados').doc(this.afs.createId()).ref,
er.getData()
);
I'll offer an answer for Firebase 9 in which the syntax differs from Firebase 8.
For Firebase 9, the equivalent of add() is addDoc() as explained at https://firebase.google.com/docs/firestore/manage-data/add-data#web-version-9_6 . It is for when you're not using batch nor transaction. As per the original problem posted, there is no equivalent of addDoc() on batch nor transaction on Firebase 9 either.
I found a way to achieve the equivalent of addDoc() for a batch on Firebase 9 by following the answer https://stackoverflow.com/a/69859144/2848676 as follows:
const batch = writeBatch(db);
const docADocRef = doc(collection(db, "DocA"));
batch.set(docADocRef, {
fieldA: "This is field of an instance of DocA"
});
const docBDocRef = doc(collection(db, "DocB"));
batch.set(docBDocRef, {
docAID: docADocRef.id
});
batch.commit();
In this example, instances of DocA and DocB are created and DocB receives a pointers to the DocA instance.
According to the docs
Behind the scenes, .add(...) and .doc().set(...) are completely equivalent, so you can use whichever is more convenient.
Perhaps this applies to batches as well?
For PHP you can try :
$batch = $db->batch();
$newCityRef = $db->collection('cities')->newDocument();
$batch->set($newCityRef , [ 'name'=>'New York City' ]);
To create a document with auto-generated ID with firestore batch, you cannot use the addDoc(). You have to use batch.set() with a reference to the document to be created as below
const db = getFirestore();
// Create a transaction to update both the product stock value and add the new stock data
const batch = writeBatch(db);
const prodRef = doc(db, `products/${productId}`);
const stockRef = doc(collection(db, `stocks`);
// newDocId = stockRef.id;
batch.set(stockRef, stock, {merge: true}); //create new document with autoId
batch.update(prodRef, {available : increment(quantity), stock: increment(quantity)});
batch.commit()
Create the reference to the collection in which you are going to add the batch data
We loop over the req.body using forEach and set the each data to be added in to the collection using the set method
We commit the data and save the data to the collection using the commit method and on success ,send a success response.
cloud firestore
Lets assume that you have list of cities and you want to write them in batch.
final CityList = FirebaseFirestore.instance.collection('cities')
WriteBatch batch = FirebaseFirestore.instance.batch();
for(CityList city in cities) {
final newShoppingItem = ShoppingList.doc();
batch.set(newShoppingItem, {
'name': city.name,
'createdAt': DateTime
.now()
.millisecondsSinceEpoch
});
}
batch.commit();
Sam Stern's answer is the correct way to do it, although if you are using AngularFire, .doc() cannot be used withouth a parameter to generate a new docId (see https://github.com/angular/angularfire/issues/1974).
The AngularFire way of doing this would be:
// Create a ref with auto-generated ID
const id = this.db.createId();
const newCityRef= this.db.collection("cities").doc(id);
// ...
// Add it in the batch
batch.set(newCityRef, { name: 'New York City' });
This worked for me and it is mentioned in the docs for PHP
$batch = $db->batch();
# Set the data for NYC
$nycRef = $db->collection('samples/php/cities')->document('NYC');
$batch->set($nycRef, [
'name' => 'New York City'
]);
# Update the population for SF
$sfRef = $db->collection('samples/php/cities')->document('SF');
$batch->update($sfRef, [
['path' => 'population', 'value' => 1000000]
]);
# Delete LA
$laRef = $db->collection('samples/php/cities')->document('LA');
$batch->delete($laRef);
# Commit the batch
$batch->commit();

MongoDB : How to find multiple documents and update at the same time?

I have mongo DB and I am using C#.Net to interact with mongo db. C# API has methods for finding a single document and updating it at the same time. For example FindOneAndUpdateAsync.
However I couldn't find any method to find multiple documents and update them at the same time asynchronously.
The code below finding and processing each document asynchronously. How do I also update that document at the same time?
public async Task<IList<IDictionary<string, string>>> DoWork()
{
var collection = _mongoDatabase.GetCollection<BsonDocument>("units");
var filterBuilder = Builders<BsonDocument>.Filter;
var filter = filterBuilder.Ne<string>("status", "INIT") &
(filterBuilder.Exists("isDone", false) |
filterBuilder.Eq<bool>("isDone", false));
// I want to pass this update filter to update the document. But not sure how
var update = Builders<BsonDocument>.Update
.CurrentDate("startTime");
var sort = Builders<BsonDocument>.Sort.Ascending("startTime");
var projection = Builders<BsonDocument>.Projection
.Include("_id")
.Include("fileName"); // for bravity i have removed other projection elements
var output = new List<IDictionary<string, string>>();
// How do i pass update filter and update the document at the same time??
await collection
.Find(filter)
.Sort(sort)
.Project(projection)
.ForEachAsync((unit) =>
{
var dictionary = new Dictionary<string, string>();
Recurse(unit, dictionary);
output.Add(dictionary);
});
return output.Count > 0 ? output : null;
}
That doesn't exist in the mongo .Net api see here.
Just use a combination of Find and UpdateManyAsync.