couchdbpouchdbcouchdb-mango

PouchDB-find automatically building selectors from variable input


I am looking for a way to adapt query fields in the db-find selector. I need this because filters access different fields which may or may not be active all the time.

I have tried two options, but none of them work:

  1. In the first option I tried to build the query as a string and let it be evaluated:
 public getFilteredItems(filters: ItemFilter[]) {
    let selectors: string[] = [];
    filters.forEach((filter: ItemFilter) => {
      selectors.push(
        "\n{\n'" +
          filter.field +
          "': { $in: \n ['" +
          filter.values.join("','") +
          "']} \n} \n "
      );
    });

    return this.getDB('items').find({
      selector: {
        $and: eval('selectors.join()'),
        // $and: selectors.join(),
        // $and: selectors,
      },
    });
  }

2: In the second try I have tried to give a variable as query field, but the syntax does not allow it.

  public getFilteredItems(filters: ItemFilter[]) {
    return this.getDB('items').find({
      selector: {
        filters[0].field:   { $in: filter.values }
      },
    });
  }

Is there any other way?

EDIT: filters look like following:

filters: [
    {
      name: 'Filtergroup Template',
      field: 'template',
      values: ['case'],
      always_active: true,
    },
   ...
]

Error messages:

For option 1, $and: eval('selectors.join()'), and $and: selectors.join(),, I get the following error:

index.es.js?26cc:74 Uncaught (in promise) TypeError: selectors.forEach is not a function
    at mergeAndedSelectors (index.es.js?26cc:74)
    at massageSelector (index.es.js?26cc:242)
    at find$1 (index-browser.es.js?5d16:1194)
    at eval (index-browser.es.js?5d16:119)
    at eval (index-browser.es.js?5d16:112)
    at PouchDB.eval (index-browser.es.js?5d16:1380)
    at eval (index-browser.es.js?a2df:138)
    at new Promise (<anonymous>)
    at PouchDB.eval (index-browser.es.js?a2df:125)
    at PouchDB.eval [as find] (index.js?dd8f:14)

If I use $and: selectors,, I will only get a note with {docs: Array(0), warning: 'no matching index found, create an index to optimize query time'}


Solution

  • Given the comments above, simply create a collection for an explicit $and

    const filters = [{
        name: 'Filter A',
        field: 'lead guitar',
        values: ['jerry']
      },
      {
        name: 'Filter B',
        field: 'rhythm guitar',
        values: ['bobby']
      }
    ];
    
    const clauses = {};
    
    filters.forEach(filter => clauses[filter.field] = {
      $in: filter.values
    });
    
    const query = {
      selector: {
        $and: [clauses]
      }
    };
    document.getElementById("content").innerText = JSON.stringify(query, undefined, 2);
    <pre id="content"></pre>

    DO note however that $and is implicit which is covered here in the CouchDB docs.