'CouchDB View, list key with duplicate count

In CouchDB I have a collection of articles. Each article has a tags property. I wrote this map function to list all tags in database

function (doc) {
   for(var i = 0; i < doc.metaKeywords.length; i++)
   emit(doc.metaKeywords[i], 1)
}

But when it list all tags, it show duplicates of tags. I want to show only one time for each tag and show duplicate number of each tags instead of emit duplicate rows of same key.

What should I do to modify this map function?



Solution 1:[1]

The map function is OK, but there is no reason to emit the value 1.

Regardless, the simple builtin reduce function _count and the right query does everything required.

Working with CouchDB demands understanding the B-tree and it's documentation has a great rundown of it in its Reduce/Rereduce documentation. I highly recommend grok'ing that information.

The snippet below highlights its usage via pouchdb. The design document specifies both map and reduce, e.g.

{      
  "_id": "_design/SO-72078037",
  "views": {
    "tags": {
      "map": `function (doc) {          
        if(doc.tags) doc.tags.forEach(tag => emit(tag));           
      }`,
      "reduce": "_count",
    }
  }
}

Straight forward stuff. To get key (tag) counts the query is as simple:

{
  reduce: true,
  include_docs: false,
  group_level: 1
}

Again, the CouchDB documentation is great - read up on group level queries

const gel = id => document.getElementById(id);

async function showReduceDocs(view) {
  let result = await db.query(view, {
    reduce: true,
    include_docs: false,
    group_level: 1
  });
  // show       
  gel('view_reduce').innerText = result.rows.map(row => JSON.stringify(row))
    .join('\n');
}

async function showViewDocs(view) {
  let result = await db.query(view, {
    reduce: false,
    include_docs: false
  });
  gel('view_docs').innerText = result.rows.map(row => JSON.stringify(row))
    .join('\n');
}

function getDocsToInstall() {
  return [{
      tags: ["A", "B", "C"]
    },
    {
      tags: ["A", "B"]
    },
    {
      tags: ["A"]
    },
    {
      // design document
      "_id": "_design/SO-72078037",
      "views": {
        "tags": {
          "map": `function (doc) {          
            if(doc.tags) doc.tags.forEach(tag => emit(tag));           
          }`,
          "reduce": "_count",
        }
      }
    },
  ];
}

const db = new PouchDB('SO-72078037', {
  adapter: 'memory'
});

(async() => {
  // install docs and show view in various forms.
  await db.bulkDocs(getDocsToInstall());
  showReduceDocs('SO-72078037/tags');
  showViewDocs('SO-72078037/tags');
})();
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/pouchdb.min.js"></script>
<script src="https://github.com/pouchdb/pouchdb/releases/download/7.1.1/pouchdb.memory.min.js"></script>
<div>View: Reduce</div>
<pre id='view_reduce'></pre>
<hr/>
<div>View</div>
<pre id='view_docs'></pre>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1