【问题标题】:How to count and do jointure like stuff on couchDB如何在 couchDB 上计算和做关节之类的东西
【发布时间】:2021-10-30 02:59:46
【问题描述】:

我目前正在尝试获取一位组织者的活动数量。

这是我的组织者文档的样子:

{
 "doc_type": "User",
 "email": "xxx@gmail.com",
 "blebleble: "blebleble",
}

这是我的事件文档的样子:

{
"doc_type": "Event",
 "email": "xxx@gmail.com",
 "blablabla: "blablabla",
}

我仍然不知道如何在两个文档之间进行某种连接并计算共享相同事件的数量。我想我可以解决两个文档共享的电子邮件,但我不知道该怎么做。我仍然在使用 CouchDB 时遇到问题。在 SQL 中似乎不是什么难事,但是对于 nosql 却找不到。

提前谢谢你。

【问题讨论】:

  • 不清楚您想通过电子邮件加入哪些字段?
  • 是的,如果不清楚,很抱歉。他们都使用相同的数据共享电子邮件字段,所以我想我可以在这个字段上加入他们以获得视图或类似的东西。

标签: couchdb


【解决方案1】:

“jointure”不是我在我的领域遇到过的一个术语,所以我只能猜测 join 是什么意思。

可以使用 CouchDB 视图进行联接,但我从 OP 中的要求中读到的是通过电子邮件获取事件计数。请参阅 CouchDB 的 Joins With Views 文档。为此,我看不到具有祖先关系的文档,而是一对多关系,即用户 ==> 事件。

考虑一下这个设计文档:

{
    "_id": "_design/SO-68999682",
    "views": {
      "user_events": {
        "map": `function (doc) {             
           if(doc.doc_type === 'Event') {                         
              emit(doc.email);
           }
        }`,
        "reduce": '_count'
      }
    }

视图的映射函数只是在适当的时候将doc.email 添加到“user_events”索引中。特别有趣的是reduce 函数指定了 built-in reduce function _count

鉴于这样的视图索引,可以将/db/_design/design-doc/_view/view-name 端点应用于例如,

查看所有活动

{
   reduce: false,
   include_docs: true
}

获取所有事件的计数

{
   reduce: true
}

获取每封电子邮件的事件计数(摘要)

{
   reduce: true,
   group_level: 1
}

获取特定电子邮件的事件计数

{
   reduce: true,
   group_level: 1,
   key: email
}

获取特定电子邮件的所有事件

{
   reduce: false,
   include_docs: true,
   key: email
}

_count reduce 内置提供了高性能。下面的 sn-p 使用非常方便且兼容的PouchDB 演示了上述内容。

async function showAllEventDocs() {
  let result = await db.query('SO-68999682/user_events', {
    reduce: false,
    include_docs: true
  });
  //show  
  gel('user_events_view').innerText = result.rows.map(row => [row.doc.email, row.doc.date].join('\t\t')).join('\n');
}

async function showEventCountTotal() {
  let result = await db.query('SO-68999682/user_events', {
    reduce: true
  });
  gel('event_count_total').innerText = result.rows[0].value;
}

async function showEventCountSummary() {
  let result = await db.query('SO-68999682/user_events', {
    reduce: true,
    group_level: 1
  });
  //show key/value (email, count)
  gel('event_count_summary').innerText = result.rows.map(row => [row.key, row.value].join('\t\t')).join('\n');
}


async function showUserEventCount(email, displayElement) {
  let result = await db.query('SO-68999682/user_events', {
    reduce: true,
    group_level: 1,
    key: email
  });
  //show value (count)
  gel(displayElement).innerText = result.rows[0].value;
}

async function showUserEvents(email, displayElement) {
  let result = await db.query('SO-68999682/user_events', {
    reduce: false,
    include_docs: true,
    key: email
  });
  //show  
  gel(displayElement).innerText = result.rows.map(row => [row.doc.email, row.doc.date].join('\t\t')).join('\n');
}

function getDocsToInstall(count) {
  const docs = [{
      "doc_type": "User",
      "email": "Jerry@gmail.com"
    },
    {
      "doc_type": "User",
      "email": "Bobby@gmail.com"
    },
    {
      "doc_type": "Event",
      "email": "Jerry@gmail.com",
      "date": getDocDate().toISOString().slice(0, 10)
    }, {
      "doc_type": "Event",
      "email": "Jerry@gmail.com",
      "date": getDocDate().toISOString().slice(0, 10)
    }, {
      "doc_type": "Event",
      "email": "Jerry@gmail.com",
      "date": getDocDate().toISOString().slice(0, 10)
    }, {
      "doc_type": "Event",
      "email": "Bobby@gmail.com",
      "date": getDocDate().toISOString().slice(0, 10)
    }, {
      "doc_type": "Event",
      "email": "Bobby@gmail.com",
      "date": getDocDate().toISOString().slice(0, 10)
    },
  ];
  // design document
  const ddoc = {
    "_id": "_design/SO-68999682",
    "views": {
      "user_events": {
        "map": `function (doc) {             
           if(doc.doc_type === 'Event') {                         
              emit(doc.email);
           }
        }`,
        "reduce": '_count'
      }
    }
  };

  docs.push(ddoc);
  return docs;
}

const db = new PouchDB('SO-68999682', {
  adapter: 'memory'
});
// install docs and show view in various forms.
(async() => {
  await db.bulkDocs(getDocsToInstall(20)); 
  await showAllEventDocs();
  await showEventCountTotal();
  await showEventCountSummary();
  await showUserEventCount('Jerry@gmail.com', 'jerry_event_count');
  await showUserEventCount('Bobby@gmail.com', 'bobby_event_count');
  await showUserEvents('Jerry@gmail.com', 'jerry_events');
  await showUserEvents('Bobby@gmail.com', 'bobby_events');
})();
const gel = id => document.getElementById(id);

function getDocDate() {
  const today = new Date();
  const day = Math.random() * 100 % today.getDay() + 1; // keep it basic
  return new Date(today.getFullYear(), today.getMonth(), day)
}
.bold {
  font-weight: bold
}

.plain {
  font-weight: normal
}
<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>

<pre>All user_events (entire view)</pre>
<pre id='user_events_view'></pre>
<hr/>
<pre>Total number of events: <span id='event_count_total'></span> events</pre>
<hr/>
<pre>Event count summary (user, count)</pre>
<pre id='event_count_summary'></pre>
<hr/>
<pre>Event count by email (specific to user)</pre>
<pre>Bobby@gmail.com has <span id='bobby_event_count'></span> events</pre>
<pre>Jerry@gmail.com has <span id='jerry_event_count'></span> events</pre>
<hr/>
<pre>Events by email</pre>
<pre class="bold">Bobby@gmail.com <pre class="plain" id='bobby_events'></pre></pre>
<pre class="bold">Jerry@gmail.com <pre class="plain" id='jerry_events'></pre></pre>
<hr/>

请注意,演示 sn-p 的文档有一个 date 字段。如果 OPs Event 文档中存在这样的字段,则将 emit 更改为

emit(doc.email + '/' + doc.date);

将允许所有上述查询以及按日期或日期范围查询的选项,我将留给读者探索的练习。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-30
    • 1970-01-01
    • 2013-11-21
    • 2010-12-29
    • 1970-01-01
    • 2012-06-15
    • 1970-01-01
    相关资源
    最近更新 更多