How can I be sure that this sequence of commands to firestore will be done completely?
FirebaseFirestore.instance
.collection('Example')
.doc(Example.id)
.collection("Example")
.doc(Example.iD)
.delete()
.then((_) => FirebaseFirestore.instance
.collection('Example')
.doc(Example.iD)
.collection("Example")
.doc(Example)
.delete())
.then((_) => FirebaseFirestore.instance
.collection("Example")
.doc(Example.id)
.delete()
.then((_) {
_privateChatInfoList.removeWhere((key, value) => key == id);
notifyListeners();
}));
To be more clear : how I can be sure that if any problem, error or bug happen will not cause an interruption between commands to just send the first or the second one only!
If you're asking how to transactionally manipulate data, I'd recommend using a transaction. If you don't need any existing data from the documents, you can also use a batched write operation, which is a bit simpler.
Related
FirebaseFirestore.instance
.collection(
'chats/${site}/conversations/${room.id}/messages')
.orderBy('createdAt', descending: true)
.where("createdAt", isGreaterThan: dateTime )
.snapshots()
.map(
(snapshot) {
So, On the first document that inserted to the firestore, the I get i a snapshot. On the second, the stream return the first and the second,
So the i get -
(Doc A)
(Doc A,Doc B)
(Doc A, Doc B, Doc C)
And so on. Is there a way to get:
(Doc A)
(Doc B)
(Doc C)
?
I reviewed your snippet and it appears you are using a Stream from the snapshot() method of a CollectionReference type. According to the documentation, this will stream events as they happen in Firestore. You mentioned that with each document inserted in Firestore, you also started getting the previous documents that were inserted before, instead of getting only the one which was just inserted (the latest). This might be related to the dateTime variable you are using to filter documents. Since you are using a greater than comparison, any documents created after the time set in the dateTime will be returned from the query. This could explain why your query returns additional documents each time a new one is added with a timestamp after the dateTime variable.
If you would like to get only the latest document added to the database each time, you can make use of a query limiter. I tested the limitToLast method to get only the latest document added and it appears to work in my testing. This method returns the very last document in a query, and in order for this to be the newest you would have to invert the process to order by ascending (oldest first) so that the newest document is at the bottom:
FirebaseFirestore firebase = FirebaseFirestore.instance;
firebase
.collection('users')
.orderBy('createdAt', descending: false) // orders by ascending order, latest document is the last
.limitToLast(1) // gets the last document, you can set how many docs to get
.get()
.then((QuerySnapshot snapshot) {
if (snapshot != null) {
// Data is available
snapshot.docs.forEach((doc) {
print(doc['firstName']);
});
} else {
print("No data found");
}
}
for everyone who reach this issue on 2022, the solution is rather simple.
You can stay with the same query but check the doc changes:
snapshot.docChanges.forEach((docChange) {
final data = docChange.doc.data() as Map;
LimitToLast won't solve your problem if the internet connection was down for a few moments and multiple updates arrived, but docChanges is all the changes since the last snapshot.
Note: You need to ignore the first time because it will return all the docs on the collection at the first time.
Thank you for reading my question.
My English may not be good enough before I ask you a question.
this my firestore structure
I'm using a flutter and I have to bring the product collection and subcollection image together from the FireStore.
I succeeded get data, but I don't know how to use it as a streambuilder.
FirebaseFirestore.instance
.collection("products")
.get()
.then((value) async => {
for (DocumentSnapshot document in value.docs)
{
log(document.data().toString()),
await document.reference
.collection("images")
.get()
.then((value) => {
for (DocumentSnapshot document
in value.docs)
{
log(document.data().toString()),
}
}),
}
});
code run log result
I looked for it for three days, but I couldn't find the answer.
Please reply.
Have a nice day. Thank you.
The only way I have found to do this is to use 2 different streambuilders, naming each snapshot differently. Use one for the products collection, then images for the other. What I would recommend is to add a field of 'images' in your product document and make it an array of string types. This will allow you to reference the images straight from each product document
I get some data from firestore. Sometimes when I called to get data, the collection is not created yet.
before calling get request, how do I check collection is exists or not?
Stream<List<ChatModel>> getChat(ChatFieldModel model) {
var ref = _db.collection('chats');
return ref
.document(model.docId)
.collection('messages')
.orderBy('timestamp', descending: true)
.snapshots()
.map((list) =>
list.documents.map((doc)=>ChatModel.fromForestore(doc)).toList());
}
I posted this before
final snapshot = await firestore.collection(roomName).getDocuments();
if (snapshot.documents.length == 0) {
//doesnt exist
}
Hope this helps
Collections are not created or deleted independently of documents. When you create a document and specify it as being part of a certain collection, that collection is created automatically if it does not already exist. Similarly, when you remove the last document in a collection, that collection will automatically be deleted. So there is really no circumstance where you need to worry about whether a collection has been created or not, and you have no explicit control over creating or deleting collections.
Usually a collection in Firestore gets deleted if no Documents exist in it.
However, there might be cases where you want to keep a history of the collection modification events, or let's say for some reason prevent Collections from being deleted.
Or for example, you want to know when a collection was created in the first place. Normally, if the Documents are deleted, and then the Collection gets created again, you will not know the initial creation date.
A workaround I can think of is the following:
Initialize each collection you want with a Document that will be specifically for keeping generic info about that collection.
For example:
This way, even if all other Documents in the Collection are deleted, you'll still keep the Collection in addition to some info that might be handy if In the future you need to get some history info about the Collection.
So to know if a Collection exists of no, you can run a query that checks for a field in Info Documents (eg CollectionInfo.exists) to know which Collections have been already created.
This is for the most recent update
final snapshot = await FirebaseFirestore.instance
.collection('collection name').get();
if ( snapshot.size == 0 ) {
print('it does not exist');
}
Feb 2022
Get QuerySnapshot and return querySnapshot.docs.isNotEmpty or isEmpty
Future<bool> isItems() async {
CollectionReference collectionReference =
_firestore.collection("users").doc(_user!.uid).collection("cart");
QuerySnapshot querySnapshot = await collectionReference.get();
return querySnapshot.docs.isNotEmpty;
}
await FirebaseFirestore.instance
.collection('collectionName')
.limit(1)
.get()
.then((snapshot) {
if (snapshot.size == 0) {
print("No collection");
}
});
I have a collection by name "trips" in Firestore. The data format is something like this
I'm trying to access documents of that Collection by using below code.
First way
try {
Firestore.instance
.collection("trips")
.where("createdByName", isEqualTo: "Suresh")
.snapshots
.listen((data) => print('Firestore response1: ${data.documents}'));
} catch (e){
print('Caught Firestore exception1');
print(e);
}
Second way
try {
Firestore.instance.collection("trips").where("createdByName", isEqualTo: "Suresh").getDocuments().then((data) {
print('Firestore response2: , ${data.documents}');
});
} catch (e){
print('Caught Firestore exception2');
print(e);
}
But, none of the above two ways is working. Don't know what I'm doing wrong.
One thing I've noticed whenever I'm removing the where("createdByName", isEqualTo: "Suresh") part from the query it's working fine. But, the moment I include that part query is returning an empty result.
I'm not sure if the screenshot is accurate but it looks like you have a trip node as well. That would put the hierarchy as trips.trip.createdByName, no? If so, it's likely that the where clause is wrong.
Ok, after two days of breaking my brain for this silly thing... this is the answer to the issue... .where('trip.createdByName', isEqualTo: "Suresh")
And, the full queries are like this...
First way
Firestore.instance.collection('trips')
.where('trip.createdByName', isEqualTo: "Suresh")
.snapshots.listen(
(data){
data.documents.forEach((doc) => print( 'Firestore response1 : ${doc.data.toString()}' ));
}
);
Second way
Firestore.instance.collection("trips")
.where("trip.createdByName", isEqualTo: "Suresh")
.getDocuments().then((string) {
string.documents.forEach((doc) => print("Firestore response2: ${doc.data.toString()}" ));
});
Hope, this will be a help. :)
I'm trying to model "memberships" with Firestore. The idea is that there are companies, users and then memberships.
The memberships collection stores a reference to a company and to a user, as well as a role as a string, e..g admin or editor.
How would I query to get the users with a certain role for a company?
This is what I currently have with some basic logging.
const currentCompanyID = 'someid';
return database
.collection('memberships')
.where('company', '==', database.doc(`companies/${currentCompanyID}`))
.where('role', '==', 'admin')
.get()
.then(snap => {
snap.forEach(function(doc) {
console.log(doc.id, ' => ', doc.data());
const data = doc.data();
console.log(data.user.get());
});
})
.catch(error => {
console.error('Error fetching documents: ', error);
});
data.user.get() returns a promise to the user, but I'd have to do that for every user which seems inefficient?
What would be the best way to approach this?
Your code is close to what you want, but there are two issues:
Your where() clause can't compare a field with a document reference, because Firestore is a classic denormalized datastore. There aren't ways to strongly guarantee that one document refers to another. You'll need to store document IDs and maintain consistency yourself. (Example below).
Queries actually return a QuerySnapshot, which includes all the docs that result from a query. So you're not getting one document at a time — you'll get all the ones that match. (See code below)
So a corrected version that fits the spirit of what you want:
const currentCompanyID = '8675309';
const querySnapshot = await database
.collection('memberships')
.where('companyId', '==', currentCompanyID)
.where('role', '==', 'admin')
.get(); // <-- this promise, when awaited, pulls all matching docs
await Promise.all(querySnapshot.map(async snap => {
const data = doc.data();
const user = await database
.collection('users')
.doc(data.userId)
.get();
console.log(doc.id, ' => ', data);
console.log(user);
});
There isn't a faster way on the client side to fetch all the users that your query refers to at once -- it's part of the trouble of trying to use a denormalized store for queries that feel much more like classic relational database queries.
If this ends up being a query you run often (i.e. get users with a certain role within a specific company), you could consider storing membership information as part of the user doc instead. That way, you could query the users collection and get all the matching users in one shot.