Search code examples
angulartypescriptgoogle-cloud-firestoreangularfirequerying

Can I make a concatenated string into a query for AngularFire?


I am trying to make a dynamic search form on a website with Angular 8, where the user can use different dropdown menus to choose what to search for in Firestore. Depending on the different choices, I have a function that makes a string that has the same form as the query should, although it's a string. But I can't figure out how to then use it together with valueChanges() like I want to, as it's still a string. It this possible?

I guess this isn't a very elegant (if at all possible) way to do this dynamic querying, but if it's possible I think it would save me valuable time at the moment. (I have also seen how to make filters with BehaviourSubjects and switchMap, so I guess that is another (better?) way if this doesn't work.)

async getRealTimeData(value) {
  this.query = await this.makeQuery(value);
  this.data = this.query.valueChanges();
}

async makeQuery(value) {
  var collection: string;
  switch (value.collection) {
    case 'X':
      collection = 'X';
      this.queryString = ".where('datetime', '>=', '2020-01-15T09:51:00.000Z')";
      break;
    case 'Y':
      collection = 'Y';
      this.queryString = ".orderBy('ID', 'asc')";
      break;
  }

  // If Z chosen, add to search string 
  if (value.Z) {
    this.queryString = this.queryString.concat(".where('Z', '==', value.Z)");
  }
  // If not viewAllUser, add list of permitted
  else if (this.authService.viewAllUser == false) {
    this.queryString = this.queryString.concat(".where('ID', 'in', this.permitted");
  }
  this.queryString = this.queryString.concat(".orderBy('datetime', 'desc')");
  // If realtime, add limit to search string
  // (If download: no limit)
  if (this.searchType == "realtime") {
    this.queryString = this.queryString.concat('.limit(100)');
  }

  this.query = this.query.concat(this.queryString).concat(')');
  console.log('Query: ',this.query);

  return this.query;
}

Solution

  • You'll want to stop using strings for defining the query. To turn a string into executable code, you'd have to eval() is, which is not a secure operation in many environments. But it's also not needed, as you can instead use a similar pattern to build the query up too.

    async makeQuery(value) {
      switch (value.collection) {
        case 'X':
          this.query = this.query.where('datetime', '>=', '2020-01-15T09:51:00.000Z');
          break;
        case 'Y':
          this.query = this.query.orderBy('ID', 'asc');
          break;
      }
    
      // If Z chosen, add to query
      if (value.Z) {
        this.query = this.query.where('Z', '==', value.Z);
      }
      // If not viewAllUser, add list of permitted
      else if (this.authService.viewAllUser == false) {
        this.query = this.query.where('ID', 'in', this.permitted);
      }
      this.query = this.query.orderBy('datetime', 'desc');
      // If realtime, add limit to search string
      // (If download: no limit)
      if (this.searchType == "realtime") {
        this.query = this.query.limit(100);
      }
    
      return this.query;
    }
    

    You'll see that the code is very similar to yours still, but now builds the actual query, instead of concatenating strings.