Flutter firestore - Check if document ID already exists - firebase

I want to add data into the firestore database if the document ID doesn't already exists.
What I've tried so far:
// varuId == the ID that is set to the document when created
var firestore = Firestore.instance;
if (firestore.collection("posts").document().documentID == varuId) {
return AlertDialog(
content: Text("Object already exist"),
actions: <Widget>[
FlatButton(
child: Text("OK"),
onPressed: () {}
)
],
);
} else {
Navigator.of(context).pop();
//Adds data to the function creating the document
crudObj.addData({
'Vara': this.vara,
'UtgƄngsdatum': this.bastFore,
}, this.varuId).catchError((e) {
print(e);
});
}
The goal is to check all the documents ID in the database and see in any matches with the "varuId" variable. If it matches, the document won't be created. If it doesn't match, It should create a new document

You can use the get() method to get the Snapshot of the document and use the exists property on the snapshot to check whether the document exists or not.
An example:
final snapShot = await FirebaseFirestore.instance
.collection('posts')
.doc(docId) // varuId in your case
.get();
if (snapShot == null || !snapShot.exists) {
// Document with id == varuId doesn't exist.
// You can add data to Firebase Firestore here
}

Use the exists method on the snapshot:
final snapShot = await FirebaseFirestore.instance.collection('posts').doc(varuId).get();
if (snapShot.exists){
// Document already exists
}
else{
// Document doesn't exist
}

To check if document exists in Firestore. Trick is to use .exists method
FirebaseFirestore.instance.doc('collection/$docId').get().then((onValue){
onValue.exists ? // exists : // does not exist ;
});

I know this is a flutter firestore topic but I just want to share my answer.
I am using Vue and I am also doing a validation if the id is already taken on firestore.
This is my solution as of firebase version 9.8.2
const load = async() => {
try {
const listRef = doc(db, 'list', watchLink.value);
let listSnapShot = await getDoc(listRef);
if(listSnapShot._document == null) {
await setDoc(doc(db, 'list', watchLink.value), {
listName: NameofTheList.value
});
throw Error('New list added');
}
else {
throw Error('List already Exist');
}
} catch (error) {
console.log(error.message);
}
}
load();
The watchLink.value is the ID that you want to check
Edit:
if you console.log(listSnapShot), the _document will be set to null if the id does not exist on firestore. See screenshot below
If it does not exist
If ID already exists

QuerySnapshot qs = await Firestore.instance.collection('posts').getDocuments();
qs.documents.forEach((DocumentSnapshot snap) {
snap.documentID == varuId;
});
getDocuments() fetches the documents for this query, you need to use that instead of document() which returns a DocumentReference with the provided path.
Querying firestore is async. You need to await its result, otherwise you will get Future, in this example Future<QuerySnapshot>. Later on, I'm getting DocumentSnapshots from List<DocumentSnapshots> (qs.documents), and for each snapshot, I check their documentID with the varuId.
So the steps are, querying the firestore, await its result, loop over the results. Maybe you can call setState() on a variable like isIdMatched, and then use that in your if-else statement.
Edit: #Doug Stevenson is right, this method is costly, slow and probably eat up the battery because we're fetching all the documents to check documentId. Maybe you can try this:
DocumentReference qs =
Firestore.instance.collection('posts').document(varuId);
DocumentSnapshot snap = await qs.get();
print(snap.data == null ? 'notexists' : 'we have this doc')
The reason I'm doing null check on the data is, even if you put random strings inside document() method, it returns a document reference with that id.

Related

Flutter firebase check email exist inside firestore collection

I need to just check if user email exist in user collection or not. Right now I am doing like this
var check = await FirebaseFirestore.instance.collection('users')
.where('email', isEqualTo: userData['email']).snapshots();
But when I print check its showing
Instance of '_MapStream<QuerySnapshotPlatform, QuerySnapshot<Map<String, dynamic>>>'
How can I check that email exist in that collection or not ? Thanks šŸ˜Š
Your check variable is a QuerySnapshot object, while you seem to want it to be a boolean that indicates whether the query had any results.
To get that:
var query = FirebaseFirestore.instance.collection('users')
.where('email', isEqualTo: userData['email']).limit(1);
var snapshot = await query.snapshots();
var check = query.size > 0;
Note that I also added a limit(1) to the query, since you never need to read more than one document to determine if any matches exist.
you can try or take reference form this method let me know if this solves your problem
static Future<bool> emailCheck(String email) async {
bool result = false;
QuerySnapshot snapshot = await
FirebaseFirestore.instance.collection('Users').get();
snapshot.docs.forEach((f) {
if (f['email'] ==email) {
result =true;
}
});
return result;
}

Flutter Firestore Update Where

I'm trying to run a query that retrieves a single row given a where clause and updates it. I understand that Firebase doesn't support an UpdateWhere operations so I'm trying to use a Transaction instead.
I'm having difficulty making it work, maybe I'm too used to sql dbs... Here's my broken code
try {
final whereQuery = _db
.doc(userPath(user))
.collection("someInnerCollection")
.where("active", isEqualTo: true)
.limit(1);
await _db.runTransaction((transaction) async {
final entry = await transaction.get(whereQuery); // This doesn't compile as .get doesn't take in a query
await transaction.update(entry, {
"someValue": "newValue",
});
});
} catch (e) {
...
}
From the test Iā€™ve made, I would suggest the following to achieve what you mention:
Based on the following answer:
As you can see from the API documentation, where() returns a Query object. It's not a DocumentReference.
Even if you think that a query will only return one document, you still have to write code to deal with the fact that it could return zero or more documents in a QuerySnapshot object. I suggest reviewing the documentation on queries to see examples.
After doing the query consult, you have to get the DocumentReference for that given result.
Then, you can use that reference to update the field inside a Batched writes
try {
final post = await firestore
.collection('someInnerCollection')
.where('active', isEqualTo: true)
.limit(1)
.get()
.then((QuerySnapshot snapshot) {
//Here we get the document reference and return to the post variable.
return snapshot.docs[0].reference;
});
var batch = firestore.batch();
//Updates the field value, using post as document reference
batch.update(post, { 'someValue': 'newValue' });
batch.commit();
} catch (e) {
print(e);
}
You are passing the DocumentSnapshot back in the update() operation instead of DocumentReference itself. Try refactoring the like this:
final docRefToUpdate = _db.collection("colName").doc("docId");
await _db.runTransaction((transaction) async {
final entry = await transaction.get() // <-- DocRef of document to update in get() here
await transaction.update(docRefToUpdate, {
// Pass the DocumentReference here ^^
"someValue": "newValue",
});
});
You can use a collection reference and then update single fields using .update().
final CollectionReference collectionReference = FirebaseFirestore.instance.collection('users');
await collectionReference.doc(user.uid).collection('yourNewCollection').doc('yourDocumentInsideNestedCollection').update({
'singleField': 'whatever you want,
});
Same code using "where"
collectionReference.doc(user.uid).collection('yourNewCollection').doc().where('singleField', isEqualTo: yourValue).update({
'singleField': 'whatever you want,
});

Firestore query on a sub Field, Flutter

I have this schema:
What I want is: numbers with specific clientUid or clientUid not null , I wrote this code, but not works:
void getNumbers({int haveClient}) {
Firestore.instance
.collection('Numbers')
.where('numbers.clientUid', isNull: false)
.snapshots()
.listen((event) {
setState(() {
_numbers = event.documents
.firstWhere(
(element) => element.documentID == 'NMafOXZZ7QWLOvegpiCdSpyhTYG3')
.data;
});
});
}
any help, thanks
I wrote an article about saving and retrieving nested objects in Flutter which you can find here (Handling Nested Objects in Firestore with Flutter).
In short, you can't query based on a nested field. Instead you'd have to download all the document in that collection and loop through them on the client or you could restructure your database so that the clientID is in a top-level array.

How can I check if a document id that already exists in Firestore using Flutter [duplicate]

I want to add data into the firestore database if the document ID doesn't already exists.
What I've tried so far:
// varuId == the ID that is set to the document when created
var firestore = Firestore.instance;
if (firestore.collection("posts").document().documentID == varuId) {
return AlertDialog(
content: Text("Object already exist"),
actions: <Widget>[
FlatButton(
child: Text("OK"),
onPressed: () {}
)
],
);
} else {
Navigator.of(context).pop();
//Adds data to the function creating the document
crudObj.addData({
'Vara': this.vara,
'UtgƄngsdatum': this.bastFore,
}, this.varuId).catchError((e) {
print(e);
});
}
The goal is to check all the documents ID in the database and see in any matches with the "varuId" variable. If it matches, the document won't be created. If it doesn't match, It should create a new document
You can use the get() method to get the Snapshot of the document and use the exists property on the snapshot to check whether the document exists or not.
An example:
final snapShot = await FirebaseFirestore.instance
.collection('posts')
.doc(docId) // varuId in your case
.get();
if (snapShot == null || !snapShot.exists) {
// Document with id == varuId doesn't exist.
// You can add data to Firebase Firestore here
}
Use the exists method on the snapshot:
final snapShot = await FirebaseFirestore.instance.collection('posts').doc(varuId).get();
if (snapShot.exists){
// Document already exists
}
else{
// Document doesn't exist
}
To check if document exists in Firestore. Trick is to use .exists method
FirebaseFirestore.instance.doc('collection/$docId').get().then((onValue){
onValue.exists ? // exists : // does not exist ;
});
I know this is a flutter firestore topic but I just want to share my answer.
I am using Vue and I am also doing a validation if the id is already taken on firestore.
This is my solution as of firebase version 9.8.2
const load = async() => {
try {
const listRef = doc(db, 'list', watchLink.value);
let listSnapShot = await getDoc(listRef);
if(listSnapShot._document == null) {
await setDoc(doc(db, 'list', watchLink.value), {
listName: NameofTheList.value
});
throw Error('New list added');
}
else {
throw Error('List already Exist');
}
} catch (error) {
console.log(error.message);
}
}
load();
The watchLink.value is the ID that you want to check
Edit:
if you console.log(listSnapShot), the _document will be set to null if the id does not exist on firestore. See screenshot below
If it does not exist
If ID already exists
QuerySnapshot qs = await Firestore.instance.collection('posts').getDocuments();
qs.documents.forEach((DocumentSnapshot snap) {
snap.documentID == varuId;
});
getDocuments() fetches the documents for this query, you need to use that instead of document() which returns a DocumentReference with the provided path.
Querying firestore is async. You need to await its result, otherwise you will get Future, in this example Future<QuerySnapshot>. Later on, I'm getting DocumentSnapshots from List<DocumentSnapshots> (qs.documents), and for each snapshot, I check their documentID with the varuId.
So the steps are, querying the firestore, await its result, loop over the results. Maybe you can call setState() on a variable like isIdMatched, and then use that in your if-else statement.
Edit: #Doug Stevenson is right, this method is costly, slow and probably eat up the battery because we're fetching all the documents to check documentId. Maybe you can try this:
DocumentReference qs =
Firestore.instance.collection('posts').document(varuId);
DocumentSnapshot snap = await qs.get();
print(snap.data == null ? 'notexists' : 'we have this doc')
The reason I'm doing null check on the data is, even if you put random strings inside document() method, it returns a document reference with that id.

How to get, set, update and delete data from the cloud firestore in Flutter?

I tried some code but getting an exception.
The Exception that I'm getting:
java.lang.IllegalArgumentException: Invalid document reference. Document references must have an even number of segments, but Users has 1
I searched for it, according to this, Document references must have an even number of segments like: Collection - document - Collection - document - Collection - document
Query for getting data from firestore:
String getIsNewUSer;
Firestore.instance.collection('Users').document(uid).get().then((DocumentSnapshot document){
print("document_build:$document");
setState(() {
getIsNewUSer=document['IsNewUser'];
print("getIsNewUSe:$getIsNewUSer");
});
});
Query for Updating data to the firestore:
Firestore.instance
.collection('Users')
.document(uid)
.updateData({
"IsNewUser":"1"
}).then((result){
print("new USer true");
}).catchError((onError){
print("onError");
});
These code line at I'm getting above Exception.
initState:
void initState() {
super.initState();
this.uid = '';
FirebaseAuth.instance.currentUser().then((val){
setState(() {
this.uid= val.uid;
print("uid_init: $uid");
});
});
}
Null safe code:
Get data:
var collection = FirebaseFirestore.instance.collection('collection');
var docSnapshot = await collection.doc('doc_id').get();
Map<String, dynamic>? data = docSnapshot.data();
Set data:
var collection = FirebaseFirestore.instance.collection('collection');
collection.add(someData);
Update data:
var collection = FirebaseFirestore.instance.collection('collection');
collection
.doc('foo_id') // <-- Doc ID where data should be updated.
.update(newData);
Delete data:
var collection = FirebaseFirestore.instance.collection('collection');
collection
.doc('some_id') // <-- Doc ID to be deleted.
.delete();
Replace this part in your queries:
Firestore.instance.collection('Users').document(uid)
with
Firestore.instance.document('Users/$uid')
Collection - document - Collection - document - Collection - document
Basically you already had the answer.
It is possible that FirebaseAuth.instance.currentUser() future didn't complete and populte this.uid. So this.uid == '' (empty string). So Firestore is throwing errror as you are trying to updated document at Users which is a collection.
You can validate this by printing this.uid before the update statement.
One way is to use helper method to update
Future<void> update(Map data) async {
final user = await FirebaseAuth.instance.currentUser();
return Firestore.instance.collection('Users').document(user.uid).updateData(data);
}
Then you can use helpr method as update({isNewUser: "1"}).then((r) {...})....
You can follow same approach for fetching the document as well.

Resources