21

I have a collection called company. All the companies are going to be stored like in my screenshot.

When I add another company, I want to check if the name already exists or not. How to perform that?

Here, "Nova" and "Tradetech" are two companies.

When I try to add "Nova" with the field name: "nova" again, I want to show a notice: "Company already exists!".

screenshot

creativecreatorormaybenot
  • 114,516
  • 58
  • 291
  • 402
Rajesh
  • 3,562
  • 7
  • 24
  • 43

5 Answers5

31

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),)),
              );
          }
        });
  }
}
Rajesh
  • 3,562
  • 7
  • 24
  • 43
  • That is really nice. Remember to accept one of the answers, as this will mark the question as answered. You should *not* **edit** your *title* with something like *"[FIXED]"*, but *accept an answer* to mark the problem as answered. – creativecreatorormaybenot Jul 01 '18 at 17:52
  • @creativecreatorormaybenot thanks bro got it i won't do that again!! – Rajesh Jul 01 '18 at 18:09
  • There is a button that looks like a tick, which will turn green once you press it. That is the one you should use to accept an answer, below the voting. E.g. you could accept your answer to mark that it solved the problem or mark someone else's answer. – creativecreatorormaybenot Jul 01 '18 at 19:42
  • @creativecreatorormaybenot sorry there was an internet problem,i have replied to you yestryday night but its not available now,anyhow yes thanks – Rajesh Jul 02 '18 at 06:09
  • Hey, How to make a QuerySnapshot, ie the dataSnapshot in your code for finding documents? – meditat Aug 23 '19 at 14:47
  • 1
    Using this code ```datasnapshot.data.containsKey("name")``` always prints out the error: ```Unhandled Exception: NoSuchMethodError: The method 'containsKey' was called on null.``` – Michael T Jul 15 '20 at 15:17
  • @RajeshJr. Can you please guide me on how to perform these same queries but on dateTime objects. – Static_Subhang Nov 09 '20 at 15:19
  • 3
    datasnapshot.data.containsKey("name") seems to be deprecated... `error: The method 'containsKey' isn't defined for the type 'Object'.` – genericUser Sep 08 '21 at 18:54
16

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())
creativecreatorormaybenot
  • 114,516
  • 58
  • 291
  • 402
  • 2
    @creativecreatormaybenot thank you so much for your concept,i have used you concept and my existing code,then i used string lenghts to make an accurate finding.and also to avoid the CASE SENSITIVE PROBLMES I always use to soore the data in lowercase in my firestore and using "toLowercase" in my textformfiled. – Rajesh Jul 01 '18 at 17:34
  • Can we use case sensitive and startswith method in flutter – Jay Mungara Oct 23 '19 at 07:51
  • only problem with this is if I'm using this logic for inserting if not exists. There can be a race condition.... so I should do the look up then insert transactionally. Any clue how to due this all in one swoop? – MobileMon Dec 14 '19 at 19:54
  • thanx is this simple and one of the easiest one – Dhananjay pathak May 08 '21 at 18:24
  • here you have to make 2 calls for case where company does not exists, Does Firestore provide any feature as to insert only if 'name' does not exists, Throw exception if already exists ? – Paritosh Agrawal May 30 '21 at 14:25
  • But I thought he is asking for field existence and not the value? – Francisca Mkina Sep 16 '21 at 08:45
6
final QuerySnapshot result =
    await Firestore.instance.collection('users').where('nickname', isEqualTo: 
    nickname).getDocuments();

final List < DocumentSnapshot > documents = result.documents;

if (documents.length > 0) { 

  //exists

} else {  

  //not exists

}
Gabriel Almeida
  • 426
  • 4
  • 7
5

Use the function:

snapshot.data!.data()!.containsKey('key_name')

to check if a field exists in your document.

PS. I just used this in my code RN and it works

Tyler2P
  • 2,324
  • 26
  • 22
  • 31
1

I know I am late. Posting for future users. Try this:

DocumentReference datab = db.collection("Company").document("Nova");

datab.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
    @Override
    public void onSuccess(DocumentSnapshot documentSnapshot) {

        if(documentSnapshot.contains("name"))
        {
            Toast.makeText(YourActivity.this, "Child exixts.", Toast.LENGTH_SHORT).show();

        }
        else
            Toast.makeText(YourActivity.this, "Doesnt exits.", Toast.LENGTH_SHORT).show();


    }
});
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Zubayr
  • 457
  • 4
  • 18
  • 1
    Hi sorry!this it too old question and thnkx for responding,by the way this can be simply done as>>> await documentref.get().the((doc)async{ int age = doc.data['age]})//here if the age==null so the field is not available, – Rajesh Aug 18 '19 at 07:45
  • It's not Flutter, It's native android code! – Kamal Panara Dec 15 '21 at 10:22