How to Check a Certain Data Already Exists in Firestore or Not

How to check a certain data already exists in firestore or not

Loading data from Cloud Firestore happens asynchronously. By the time you return from alreadyBooked, the data hasn't loaded yet, onSuccess hasn't run yet, and flag still has its default value.

The easiest way to see this is with a few log statements:

private boolean alreadyBooked(final String boname, final String bodept, final String botime) {
CollectionReference cref=db.collection("bookingdetails");
Query q1=cref.whereEqualTo("time",botime).whereEqualTo("dept",bodept);
System.out.println("Starting listener");
q1.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
System.out.println("Got data from Firestore");
}
});
System.out.println("Returning");
}

If you run this code it will print:

Starting listener

Returning

Got data from Firestore

That's probably not the order you expected. But it perfectly explains why you always get false when calling alreadyBooked: the data simply didn't come back from Firestore in time.

The solution for this is to change the way you think about the problem. Your current code has logic: "First check if it is already booked, then add a new item". We need to reframe this as: "Start checking if it is already booked. Once we know that is isn't, add a new item." In code this means that all code that needs data from Firestore must be inside the onSuccess or must be called from there.

The simplest version is to move the code into onSuccess:

private void alreadyBooked(final String boname, final String bodept, final String botime) {
CollectionReference cref=db.collection("bookingdetails");
Query q1=cref.whereEqualTo("time",botime).whereEqualTo("dept",bodept);
q1.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
boolean isExisting = false
for (DocumentSnapshot ds : queryDocumentSnapshots) {
String rname, rdept, rtime;
rname = ds.getString("name");
rdept = ds.getString("dept");
rtime = ds.getString("time");
if (rdept.equals(botime)) {
if (rtime.equals(botime)) {
isExisting = true;
}
}
}
if (!isExisting) {
// TODO: add item to Firestore
}
}
});
}

While this is simple, it makes alreadyBooked less reusable since now it contains the code to insert the new item too. You can solve this by defining your own callback interface:

public interface AlreadyBookedCallback {
void onCallback(boolean isAlreadyBooked);
}

private void alreadyBooked(final String boname, final String bodept, final String botime, AlreadyBookedCallback callback) {
CollectionReference cref=db.collection("bookingdetails");
Query q1=cref.whereEqualTo("time",botime).whereEqualTo("dept",bodept);
q1.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
for (DocumentSnapshot ds : queryDocumentSnapshots) {
String rname, rdept, rtime;
rname = ds.getString("name");
rdept = ds.getString("dept");
rtime = ds.getString("time");
if (rdept.equals(botime)) {
if (rtime.equals(botime)) {
isExisting = true;
}
}
}
callback.onCallback(isExisting)
}
});
}

And then you call it as:

alreadyBooked(boname, bodept, botime, new AlreadyBookedCallback() {
@Override
public void onCallback(boolean isAlreadyBooked) {
// TODO: insert item
}
});

Also see (many of these are for the Firebase Realtime Database, where the same logic applies):

  • getContactsFromFirebase() method return an empty list
  • Doug's blog post on asynchronous callbacks
  • Setting Singleton property value in Firebase Listener
  • Android + Firebase: synchronous for into an asynchronous function
  • Is it possible to synchronously load data from Firebase?
  • Querying data from firebase

How can I tell if I value already exists in Firebase Firestore?

There isn't any function to check if a field exists in a document. You'll have to fetch the document and check for it's existence:

let docRef = Firestore.firestore().collection(user!.uid).document(docID)

docRef.getDocument { (document, error) in
if let document = document, document.exists {
let data = document.data()
// Check if the field exists in data
} else {
print("Document does not exist")
}
}

javascript - Firestore checking if username already exists

To be straight forward you can just try this code:

const username = ""
const userNameDoc = await firebase.firestore().collection("users").where("username", "==", username).get()
if(!userNameDoc.empty) {
console.log("This username is already taken!");
}

But as this is all frontend so this can be bypassed if anyone wants to. All this requires you to give all users access to the whole users collection which won't be ideal. So you should ideally use a cloud function or you own server environment for better security.

For example, you can block all direct requests to Firestore collection using security rules and create users using the Admin SDK in cloud functions.

You can use the code below in your cloud function to create a new user by checking if the username is still valid.


exports.createNewUser = functions.https.onCall(async (data, context) => {
const userEmail = data.email
const userName = data.name
const userPass = data.password
const userNameDoc = await admin.firestore().collection("users").where("username", "==", username).get()
if(!userNameDoc.empty) {
console.log("This username is already taken!");
return {result: "Username is already taken!"}
}
return admin
.auth()
.createUser({
email: 'user@example.com',
password: userPassword,
displayName: userName,
})
.then((userRecord) => {
// See the UserRecord reference doc for the contents of userRecord.
console.log('Successfully created new user:', userRecord.uid);
return {result: "User Created!"}
})
.catch((error) => {
console.log('Error creating new user:', error);
return {result: error}
});
});

The 2nd method is way more secure than first one for your Firestore DB.

How to check if a document exists in a firestore collection?

final snapShot = await Firestore.instance.collection('users').document("docID").get();

if (snapShot.exists){

}

You can check here

Flutter firestore check if document with specific id exists

The following line from your code returns a QuerySnapshot which is not nullable:

FirebaseFirestore.instance.collection('doc_folder').where("userId", isEqualTo: currentUser!.uid).get()

and you assign the returned value of QuerySnapshot to snap and perform the following:

snap != null ? ... : ...

However, this condition will be true regardless of whether a document exists.

You should instead check docs property from QuerySnapshot, which is a list of the document snapshots returned for your query.

I'd prefer the widget of FutureBuilder over calling getData() in initState for this example to make it clear:

@override
Widget build(BuildContext context) {
return FutureBuilder<QuerySnapshot>(
future: crud.getData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.docs.isNotEmpty) {
// Document exists
} else {
// Document does not exist
}
} else {
// Show a loading widget
// ...
}
},
);
}

Full Example

class Crud {
Future<QuerySnapshot> getData() async {
return await FirebaseFirestore.instance
.collection('doc_folder')
.where("userId", isEqualTo: currentUser!.uid)
.get();
}
}

class MyPage extends StatefulWidget {
@override
_MyPageState createState() => _MyPageState();
}

class _MyPageState extends State<MyPage> {
final crud = Crud();

@override
Widget build(BuildContext context) {
return FutureBuilder<QuerySnapshot>(
future: crud.getData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final querySnaphost = snapshot.data; // Get query snapshot

if (querySnaphost.docs.isNotEmpty) {
// Document exists
final documentSnapshot =
querySnaphost.docs.first; // Get document snapshot
return Text('${documentSnapshot.data()}'); // Get the data
} else {
// Document does not exist
return Text('Document does not exist.');
}
} else {
// Show a loading widget
return CircularProgressIndicator();
}
},
);
}
}

Firestore query - checking if username already exists

To solve this, please use the following lines of code:

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference allUsersRef = rootRef.collection("all_users");
Query userNameQuery = allUsersRef.whereEqualTo("username", "userNameToCompare");
userNameQuery.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot document : task.getResult()) {
if (document.exists()) {
String userName = document.getString("username");
Log.d(TAG, "username already exists");
} else {
Log.d(TAG, "username does not exists");
}
}
} else {
Log.d("TAG", "Error getting documents: ", task.getException());
}
}
});

In which userNameToCompare is of type String and is the user name of the user with which you want to make the comparison.

Firebase Firestore: How to check if the document exists before writing data?

The set() method with the merge option is what you are looking for:

If the document does not exist, "it will set a new document to the path", if it exists "it will just update the data".

You have to do as follows:

const ref = firebase.firestore().collection('posts').doc('post_id');
ref.set(
{foo: 'bar', bar: 'foo'},
{merge: true}
);

Check if Field Already exists in Flutter Firestore

I have solved this issue with the follwoing code, thanks for helping me!

IN THE FOLLOWING CODE I USED TO FIND

1)A DOCUMENT IS EXISTING OR NOT?

2)A KEY IS EXISTING OR NOT?

3)A VALUE IS EXISTING OR NOT?

SIMPLE METHOD
//////////////////////////////////////////////////////////////////////


import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';

String myText1 = 'temp1';
String myText2 = 'temp2';
String myText3 = 'temp3';
String myText4 = 'temp4';
String myText5 = 'temp5';
String myText6 = 'temp6';
StreamSubscription<DocumentSnapshot> subscription;
final DocumentReference documentReference =
Firestore.instance.document("company/Nova");

class Clean extends StatefulWidget {
@override
_CleanState createState() => _CleanState();
}

class _CleanState extends State<Clean> {
@override
void initState() {
super.initState();
subscription = documentReference.snapshots().listen((datasnapshot) {
//FINDING A SPECIFICDOCUMENT IS EXISTING INSIDE A COLLECTION

if (datasnapshot.exists) {
setState(() {
myText1 = "Document exist";
});
} else if (!datasnapshot.exists) {
setState(() {
myText2 = "Document not exist";
});
}

//FINDING A SPECIFIC KEY IS EXISTING INSIDE A DOCUMENT

if (datasnapshot.data.containsKey("name")) {
setState(() {
myText3 = "key exists";
});
} else if (!datasnapshot.data.containsKey("name")) {
setState(() {
myText4 = "key not exists";
});
}


//FINDING A SPECIFIC VALUE IS EXISTING INSIDE A DOCUMENT

if (datasnapshot.data.containsValue("nova")) {
setState(() {
myText5 = "value exists";
});
} else if (!datasnapshot.data.containsValue("nova")) {
setState(() {
myText6 = "value not exists";
});
}
});
}

@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
new Text(myText1),
new Text(myText2),
new Text(myText3),
new Text(myText4),
new Text(myText5),
new Text(myText6),
],
);
}
}

MY OLD COMPLEX METHOD BASED ON MY EXISTING CODE
////////////////////////////////////////////////////////

Concept

it has a search bar,when you type it will show the company name ie existing or not in

A Card and a RaisedButton. I am using lower case in Firestore in order to avoid the search error. I have forced the TextFormField output to be lower case with toLowercase(). You can change it to your own text format.

Code

//if the name is not existing it will show a raised button so u can clcik on that to 
//go to a COMPANY ADDING PAGE,otherwise it will only show a **CARD** so that you
//can't go to the next page to add your company


//code:

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
import './fullscreen.dart';

const blue = 0xFF3b78e7;
String filter = '';
StreamSubscription<DocumentSnapshot> subscription;

final TextEditingController _usercontroller = new TextEditingController();

class CheckAvail extends StatefulWidget {
@override
HomeState createState() => HomeState();
}

class HomeState extends State<CheckAvail> {
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: false,
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
// CHILD1
new Flexible(
child: StreamBuilder(
stream: Firestore.instance
.collection('company')
.where('name', isGreaterThanOrEqualTo: filter.toLowerCase())
.limit(1)
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return new Column(
children: <Widget>[
new Card(
elevation: 5.0,
child: new Image.asset('assets/progress.gif'),
)
],
);
} else {
return FirestoreListView1(documents: snapshot.data.documents);
}
},
),
),

new Card(
elevation: 0.0,
color: Colors.white,
shape: new RoundedRectangleBorder(
borderRadius: BorderRadius.circular(60.0)),
child: Container(
padding: new EdgeInsets.only(left: 8.0),
child: new TextField(
controller: _usercontroller,
onChanged: (String z) {
setState(() {
filter = z;
});
},
decoration: const InputDecoration(
hintText: "Search...",
hintStyle: TextStyle(
fontFamily: 'roboto',
color: Colors.black38,
fontSize: 16.0,
letterSpacing: -0.500),
fillColor: Colors.white,
border: InputBorder.none,
),
),
),
),
],
),
backgroundColor: Color(blue),
);
}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class FirestoreListView1 extends StatelessWidget {
final List<DocumentSnapshot> documents;
FirestoreListView1({this.documents});
@override
Widget build(BuildContext context1) {
return ListView.builder(
itemCount: documents.length,
padding: new EdgeInsets.all(1.0),
itemBuilder: (BuildContext context1, int index) {
String name = documents[index].data['name'];
if (name.contains(filter.toLowerCase()) &&
name.length == filter.length) {
return new Container(
padding: new EdgeInsets.only(top: 45.0),
child: new Card(
child: new Text(
"Error:Already a Company Exists with this name\nTry another name")),
);
} else {
return (filter.length >= 1)
? new Container(
padding: new EdgeInsets.only(top: 15.0),
child: new RaisedButton(
onPressed: () => Navigator.push(
context1,
new MaterialPageRoute(
builder: (context1) => new NextPage(
value1: name,
))),
disabledColor: Colors.white,
child: new Text(
"Good!You can use this company name",
),
),
)
: new Container(padding: new EdgeInsets.only(top: 250.0),
child: new Card(child: new Text("CHECK IF YOUR COMPANY NAME \n AVAILABLE OR NOT",style: new TextStyle(fontSize: 20.0),)),
);
}
});
}
}


Related Topics



Leave a reply



Submit