How to query PouchDB with SQL-like operators

爱⌒轻易说出口 提交于 2020-01-16 03:20:07

问题


Being relatively new to PouchDB/CouchDB, I'm still trying to wrap my head around how to use the map/reduce correctly in different cases.

Supposed that I have document structure like this:

{
  _id: 'record/1',
  labels: {
    // many-to-many relationship
    'label/1': true, // let's assume that this is 'Label A'
    'label/3': true, // 'Label C'
    'label/4': true // 'Label D'
  }
},
{
  _id: 'record/2',
  labels: {
    'label/1': true, // 'Label A'
    'label/2': true // 'Label B'
  }
}

What are the correct ways to define view for db.query function to search:

  1. records with 'Label A' or 'Label B'
  2. records with 'Label A' and 'Label B'

回答1:


There are no OR operations in PouchDB/CouchDB mapreduce queries, so you would have to break it up into two separate queries.

Eventually these kinds of operations will be supported in pouchdb-find, but as of this writing, $or hasn't been implemented yet.




回答2:


As much as I wanted to use the pouchdb-find plugin, I couldn't find a way to achieve what I needed. Instead I used a workaround:

Change the document structure to store label IDs in an array

{_id: 'record/1', name: 'Record 1', labels: ['label/1', 'label/2', 'label/3']},
// may not be sorted when being stored
{_id: 'record/2', name: 'Record 2', labels: ['label/1', 'label/5', 'label/7', 'label/3']},
{_id: 'record/3', name: 'Record 3', labels: ['label/2', 'label/3', 'label/4', 'label/5']}

Create a design document

It will emit multiple complex keys for each record to represent all possible label-mappings in an ascending order. The map function will utilize a recursive process to generate the keys:

{
  _id: '_design/records-with-labels',
  views: {
    'records-with-labels': {
      map: function(doc) {
        // important: sort them so that the required keys to be created are lesser
        var labelIds = doc.labels.sort();
        var lastIx = labelIds.length - 1;

        var emitKey = function emitKey(currentKey, currentIx) {
          console.log('emitting: ' + currentKey.join(',') + ' for ' + doc._id);
          emit(currentKey, null);

          var nextIx = currentIx + 1;

          for (var jumpIx = nextIx + 1; jumpIx <= lastIx; jumpIx++) {
            var jumpedLabelId = labelIds[jumpIx];
            var jumpingKey = currentKey.concat([jumpedLabelId]);

            console.log('emitting: ' + jumpingKey.join(',') + ' for ' + doc._id);
            emit(jumpingKey, null);
          }

          if (nextIx > lastIx) {
            return;
          }

          var nextLabelId = labelIds[nextIx];

          currentKey.push(nextLabelId);

          emitKey(currentKey, currentIx + 1);
        };

        labelIds.forEach(function(labelId, i) {
          emitKey([labelId], i);
        });

      }.toString()
    }
  }
}

For example, the document record/1 will have these keys generated:

emitting: label/1 for record/1
emitting: label/1,label/3 for record/1
emitting: label/1,label/2 for record/1
emitting: label/1,label/2,label/3 for record/1
emitting: label/2 for record/1
emitting: label/2,label/3 for record/1
emitting: label/3 for record/1

Querying

I just need to ensure that the query labels are sorted in ascending order.

To query records that have 'label/1' and 'label/3':

Db.query('records-with-labels', {
  key: ['label/1', 'label/3']
});

To query records that have 'label/3' or 'label/3':

Db.query('records-with-labels', {
  keys: [['label/1'], ['label/3']]
});

This will give us duplicated records that has both labels, but a reduce function should help eliminating them.

Conclusion

For now I don't know if there is a better solution, but this is good enough for me because in my case, a record will not have too many labels.

If you have better suggestions, please comment or edit the answer.




回答3:


This is an older post. However, It is possible to use underscore.js to help with some of the queries. It can help pull out the data you want without having to make several trips to the database (unless you want).



来源:https://stackoverflow.com/questions/28806853/how-to-query-pouchdb-with-sql-like-operators

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!