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),)),
              );
          }
        });
  }
}

You can simply use a where query to only receive documents that have that name and then check whether you get documents. Here is an async example method that would perform what you want to know.

Example method

Future<bool> doesNameAlreadyExist(String name) async {
  final QuerySnapshot result = await Firestore.instance
    .collection('company')
    .where('name', isEqualTo: name)
    .limit(1)
    .getDocuments();
  final List<DocumentSnapshot> documents = result.documents;
  return documents.length == 1;
}

As you can see, I am only receiving documents, where the name field matches the given name. I also add limit(1) to make sure that I do not unnecessarily retrieve more than 1 document (which would never happen in theory) and then I just check if the length of all documents in the company collection is equal to 1 or not. If it is equal to 1, there already is a company that has that name and otherwise not.

You could also remove the limit(1) and make the check documents.length > 1 and that would work too, but might retrieve unnecessary documents.

Example implementation

@override
Widget build(BuildContext context) {
  return FutureBuilder(
    future: doesNameAlreadyExist('nova'),
    builder: (context, AsyncSnapshot<bool> result) {
      if (!result.hasData)
        return Container(); // future still needs to be finished (loading)
      if (result.data) // result.data is the returned bool from doesNameAlreadyExists
        return Text('A company called "Nova" already exists.');
      else
        return Text('No company called "Nova" exists yet.');
    },
  );
}

Here, I am not displaying an error message, which would be easily possible with the example method as well. However, the build method of some widget is used. This would e.g. work in a dialog, but I decided to do it to keep it simple and understandable. The FutureBuilder takes in doesNameAlreadyExist, in this case with the name "Nova" from your question and will, in the end, return a Text widget stating whether the name already exists.

Be careful

The where query is case-sensitive. This means that the check would not work if you typed e.g. "noVa" instead of "nova". As this might be important to you, you can make use of this nice method, where you would create an extra field that is insensitive, e.g. all letters are small and then you would simple query like this:

.where('name_insensitive', isEqualTo: name.toLowerCase())