PouchDB-find automatically building selectors from variable input

187 Views Asked by At

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'}

1

There are 1 best solutions below

0
RamblinRose On BEST ANSWER

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.