skip to Main Content

I have written Flutter code involving Firebase and Firestore for retrieving data regarding the current user immediately after their signing-in.

My expectation was for Firestore to confirm data within Firestore, but instead Firestore has requested an index.

The problem I have is having no clue on how to produce the index being requested.

The code is as follows:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart' as auth;

import '../widgets/textfield_try.dart';

class LoginScreen extends StatelessWidget {
  LoginScreen({super.key, this.onTap});

  TextEditingController emailController = TextEditingController();
  TextEditingController passwordController = TextEditingController();
  auth.FirebaseAuth _auth = auth.FirebaseAuth.instance;
  FirebaseFirestore _dB = FirebaseFirestore.instance;
  Function()? onTap;
  static const source = Source.serverAndCache;

  Future<void> signUserIn() async {
    await auth.FirebaseAuth.instance.signInWithEmailAndPassword(
        email: emailController.text, password: passwordController.text);
    if (_auth != null) {
      try {
        final docRef = await _dB.collectionGroup('signInData').where(
            'eAddress', isEqualTo: _auth.currentUser!.email).get().then((
            value) {
          final userData = value.docs.toList();
          print(userData);
        });
      } on Exception catch (e) {
        print(e);
      }
    }
  }

@override
Widget build(BuildContext context) {
  return MaterialApp(
    home: Scaffold(
      resizeToAvoidBottomInset: false,
      backgroundColor: Colors.blue[900],
      body: SafeArea(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Padding(padding: EdgeInsets.only(top: 0, bottom: 37)),

              TextField_Try(
                  hintText: 'Username',
                  obscureText: false,
                  controller: emailController),

              Padding(padding: EdgeInsets.only(top: 0, bottom: 0)),

              Padding(
                  padding: EdgeInsets.only(
                      top: 8.0, left: 8.0, right: 8.0, bottom: 28.0),
                  child: TextField_Try(
                    hintText: '**************',
                    obscureText: true,
                    controller: passwordController,
                  )),

              Padding(padding: EdgeInsets.only(bottom: 10)),

              ElevatedButton(onPressed: signUserIn, child: Text('Sign In')),

              Padding(padding: EdgeInsets.only(bottom: 25)),
            ],
          ),
        ),
      ),
    ),
  );
}
}

Flutter’s response to the code is:

D/FirebaseAuth(12349): Notifying id token listeners about user ( ************************ ).
I/flutter (12349): [cloud_firestore/failed-precondition] Operation was rejected because the system is not in a state required for the operation's execution. If performing a query, ensure it has been indexed via the Firebase console.

My question is, how is an index for a collection-group query based on a single collection-id produced?

Thank you for considering my question.

2

Answers


  1. Chosen as BEST ANSWER

    After hearing of the solution posted and saluted here, I noticed another way in which Firestore permits the creation of an index, and in this particular way, Firestore checks the proposed index and offers a link to create it for you automatically:

    So, on the Firestore first screen, notice options to create indexes, but also notice the option to build a query (as shown in the photo below)

    enter image description here

    If you select the Query-builder option you'll be introduced to a menu that automatically incorporates your Firestore's collection and field names (as shown in the photo below)

    enter image description here

    You can add other features to the query, like the ordering of results (as shown below)

    enter image description here

    If you run the query that you are proposing and Firestore decides that that query requires an index, then Firestore will offer you a link towards having that index created for you automatically (as seen below)

    enter image description here

    Okay, so that's everything, and now you know two ways of creating an index for Firestore's collection-group queries ..... Haaaappy coding : )


  2. Since you’re querying collectionGroup('signInData'), you’ll need to create an index on that collection group. In your case you need a single-field index on the eAddress field of the signInData collection group.

    To do this in the Firebase console:

    1. Go to the Firestore indexes page in the Firebase console
    2. Click the Single field panel, since you want to add an index on a single field.
    3. Click the Add excemption button near the bottom of the panel

    enter image description here

    1. Enter signInData in the Collection ID field and eAddress as the Field path.
    2. Check the Collection group box

    enter image description here

    Finally: click Next and then Save


    Here’s an example of such an exemption/index I created for this use-case:

    enter image description here

    And the Dart/Flutter code that I then used to query this collection group through that index:

    var group = FirebaseFirestore.instance.collectionGroup('signInData');
    var query = group.where('eAddress', isEqualTo: '[email protected]');
    
    query.get().then((querySnapshot) {
      print('Got ${querySnapshot.size} results');
      for (var doc in querySnapshot.docs) {
        print(doc.reference);
      }
    });
    

    I initially tested it with JavaScript code using the modular SDK, so here’s that too:

    let group = collectionGroup(db, 'signInData');
    let q = query(group, where('eAddress', '==', '[email protected]'));
    
    getDocs(q).then((querySnapshot) => {
      console.log(`Got ${querySnapshot.docs.length} results`);
      querySnapshot.forEach((doc) => {
        console.log(doc.ref);
      })
    })
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search