【问题标题】:How to query PouchDB with SQL-like operators如何使用类似 SQL 的运算符查询 PouchDB
【发布时间】:2016-03-17 01:11:03
【问题描述】:

作为 PouchDB/CouchDB 的新手,我仍在努力思考如何在不同情况下正确使用 map/reduce。

假设我有这样的文档结构:

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

db.query函数定义视图的正确方法是什么:

  1. 带有“标签 A”“标签 B”的记录
  2. 带有“标签 A”“标签 B”的记录

【问题讨论】:

  • 看看here多个 WHERE 和 OR 子句的答案应该对您有所帮助。

标签: couchdb pouchdb


【解决方案1】:

PouchDB/CouchDB mapreduce 查询中没有OR 操作,因此您必须将其分成两个单独的查询。

pouchdb-find 最终将支持这些类型的操作,但在撰写本文时,$or 尚未实现。

【讨论】:

  • 这个插件看起来很有前途。虽然我不能在这种情况下使用它,但我希望在其他情况下使用它。
【解决方案2】:

尽管我想使用pouchdb-find 插件,但我找不到实现我需要的方法。相反,我使用了一种解决方法:

更改文档结构以将标签 ID 存储在数组中

{_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']}

创建设计文档

它将为每条记录发出多个复杂的键,以升序表示所有可能的标签映射。 map 函数将利用递归过程来生成密钥:

{
  _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()
    }
  }
}

例如,文档record/1 将生成以下密钥:

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

查询

我只需要确保查询标签按升序排序即可。

查询具有“label/1”“label/3”的记录:

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

查询具有“label/3”“label/3”的记录:

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

这将为我们提供具有两个标签的重复记录,但 reduce 函数应该有助于消除它们。

结论

目前我不知道是否有更好的解决方案,但这对我来说已经足够了,因为就我而言,一条记录不会有太多标签。

如果您有更好的建议,请评论或编辑答案。

【讨论】:

    【解决方案3】:

    这是一篇较早的帖子。但是,可以使用 underscore.js 来帮助处理一些查询。它可以帮助提取您想要的数据,而无需多次访问数据库(除非您愿意)。

    【讨论】:

      猜你喜欢
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-07
      • 2016-04-09
      相关资源
      最近更新 更多