0

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

Yuehai
  • 1,165
  • 1
  • 10
  • 20
  • What does your filters structure look like? What errors are you getting? How about an example document? For example I can only guess that `filters[0].field: {whatever}` would not work, rather `[filters[0].field]: {whatever}`. – RamblinRose Nov 01 '21 at 21:08
  • I have include some additional information in the OP that you requested. – Yuehai Nov 02 '21 at 14:41
  • `[filters[0].field]: { $in: filters[0].values },` actually works, but how could I generalize this and do it for all elements of `filters`? – Yuehai Nov 02 '21 at 14:42
  • Well that's another layer of abstraction which beckons the question, is there a need to define logic relationships amongst filters e.g. $and filter1 ($and filter2 $or filter3)? Also, [this](https://stackoverflow.com/questions/66706361/mango-index-does-not-contain-a-valid-index-for-this-query-even-when-specified) might help regarding the index not found issue. – RamblinRose Nov 02 '21 at 15:01
  • The idea is that the query should only return items that pass all specified filters. – Yuehai Nov 02 '21 at 15:29

1 Answers1

0

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.

RamblinRose
  • 4,883
  • 2
  • 21
  • 33