【问题标题】:Extend query function to support multiple search criteria in CouchDB/PouchDB扩展查询功能以支持 CouchDB/PouchDB 中的多个搜索条件
【发布时间】:2022-01-26 01:59:02
【问题描述】:

我正在尝试统计具有level: 2completed: true 的文档。但是,我很难在查询函数中引入另一个标准。目前,从代码中可以看出;它只是打印出具有completed: true 的文档。如何扩展此查询以支持另一个查询参数,例如 level

[{
 _id: 1,
 name: 'Test_01',
 level: 1,
 completed: false
},
{
 _id: 2,
 name: 'Test_02',
 level: 2,
 completed: true
},
{
 _id: 3,
 name: 'Test_01',
 level: 3,
 completed: false
}]
const myMapReduceFun = {
 map: (doc) => {
  emit(doc.completed);
 }.toString(),
 reduce: '_count'
};

db.query(myMapReduceFun, {
 key: true, reduce: true
})
.then((result) => {
 console.log(result)
})

【问题讨论】:

  • 我发现的另一种选择是使用 Mango Queries,我可以添加多个搜索查询,但似乎不支持任何 reduce 功能?
  • 我必须指出_id必须是一个字符串。
  • 对,在这里输入时忘记了引号。

标签: mapreduce couchdb pouchdb


【解决方案1】:

这可以通过 map/reduce 轻松完成。一种策略是使用复杂的键,另一种策略是在字符串中使用巧妙的分界。

我更喜欢复杂的密钥,因为它不需要组装密钥或其他基于字符串的猴子业务。

考虑演示中的设计文档:

{
    _id: "_design/my_index",
    views: {
        completed_str: {
            map: `function (doc) { 
            emit(doc.completed + '/' + doc.level + '/')
          }`,
        },
        completed_complex: {
            map: `function (doc) { 
            emit([doc.completed,doc.level])
          }`,
        },
    },
}
  • completed_str 使用连接和“/”为已完成和级别创建两个字段
  • completed_complex 使用数组创建复杂键

在下面的 sn-p 中,我包含了两种方法的示例。关键(没有双关语)是首先发出“完成”字段,然后发出“级别”字段。

在处理查询时,请注意视图返回的值 Key 字段的差异。

const gel = id => document.getElementById(id);
const g_view_result = 'view_result';

function getQuery() {
  let view = gel('view').value;
  let completed = gel('completed').value === 'true';
  let level = parseInt(gel('level').value, 10);
  if (view === 'complex') {
    // use complex key view
    return {
      view: "my_index/completed_complex",
      params: {
        reduce: false,
        include_docs: false,
        start_key: [completed, level],
        end_key: [completed, level],
      }
    }
  }
  // use simple string view
  return {
    view: "my_index/completed_str",
    params: {
      reduce: false,
      include_docs: false,
      start_key: [completed, level, ''].join('/'),
      end_key: [completed, level, ''].join('/'),
    }
  }
}

async function query() {
  try {
    let html = [];
    const view_result = gel(g_view_result);
    view_result.innerText = '';
    let query = getQuery();
    let docs = await db.query(query.view, query.params);
    html.push(['ID', 'Key'].join('\t'));
    html.push(['----', '--------'].join('\t'));
    docs.rows.forEach(row => {
      html.push([row.id, row.key].join('\t'));
    })
    view_result.innerText = html.join('\n');
  } catch (e) {
    console.log('err: ' + e);
  }
}

// canned test documents
function getDocsToInstall() {
  return [{
      _id: "1",
      name: 'Test_01',
      level: 1,
      completed: false
    },
    {
      _id: "2",
      name: 'Test_02',
      level: 2,
      completed: true
    },
    {
      _id: "3",
      name: 'Test_01',
      level: 3,
      completed: false
    },
    {
      _id: "4",
      name: 'Test_4',
      level: 3,
      completed: true
    },
    {
      _id: "5",
      name: 'Test_05',
      level: 2,
      completed: true
    },
    {
      "_id": "_design/my_index",
      "views": {
        "completed_str": {
          "map": `function (doc) { 
              emit(doc.completed + '/' + doc.level + '/')
            }`
        },
        "completed_complex": {
          "map": `function (doc) { 
              emit([doc.completed,doc.level])
            }`
        }
      }
    }
  ]
}

let db;

async function initDb() {
  db = new PouchDB('test', {
    adapter: 'memory'
  });
  return db.bulkDocs(getDocsToInstall());
}


(async() => {
  try {
    await initDb();
  } catch (e) {
    console.log(e);
  }
})();
<script src="https://cdn.jsdelivr.net/npm/pouchdb@7.1.1/dist/pouchdb.min.js"></script>
<script src="https://github.com/pouchdb/pouchdb/releases/download/7.1.1/pouchdb.memory.min.js"></script>
<label for="completed">Completed:</label>
<select name="completed" id="completed">
  <option value="true">True</option>
  <option value="false">False</option>
</select>
<label for="level">Level:</label>
<select name="level" id="level">
  <option value="0">0</option>
  <option value="1">1</option>
  <option value="2" selected>2</option>
  <option value="3">3</option>
</select>
<label for="view">View:</label>
<select name="view" id="view">
  <option value="complex">Complex Key</option>
  <option value="simple">Simple String Key</option>
</select>
<button id="query" onclick="query()">Query</button>
<div style='margin-top:2em'></div>
<pre id='view_result'>
</pre>

【讨论】:

  • 澄清一下,编码字符串可能适用于文本字段,因为它允许匹配部分字段,对于原始值(整数、布尔值)复杂键是我的偏好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多