【问题标题】:Replace multiple joins in SQL with CouchDB views用 CouchDB 视图替换 SQL 中的多个连接
【发布时间】:2012-05-10 00:29:07
【问题描述】:

我正在为我的应用程序实现过滤器功能,但在 CouchDB 上编写视图时遇到了问题。在 SQL 中,这将是一个具有多个连接的语句。如何替换 CouchDB 中的多个联接。本文介绍单连接:http://www.cmlenz.net/archives/2007/10/couchdb-joins。但是,我不清楚如何将此方法扩展到多重连接。

想象一下我的对象有十几个属性,每个属性都可以有自己的过滤器。为简单起见,我们假设它只有两个属性。如果我们能解决这个问题,我们或许可以将其扩展到任意数量的属性。

我的应用程序需要支持一堆 AND 过滤器。例如。找到位置在(“西雅图”,“纽约”)和开始时代> = 1336608413的所有会话。我还需要保留过滤器设置。

在 SQL 中,我有两个表:Session 和 Filter。然后我在 Session 和 Filter 表之间为每个过滤条件加入一个连接,以获取所有过滤的会话。

Session Table
location    start-epoch    
Seattle     1336608413     

Filter Table
Name        Value
location    Seattle
location    New York
start-epoch 1336608413     


Query:
select * 
from Session s 
where exists (select 1 from Filter f where f.name = 'location' and f.value = s.location)
     and exists (select 1 from Filter f on f.name = 'start-epoch' and s.start-epoch >= f2.value)

在 CouchDB 中:

{"type":"session", "location":"Seattle", "start-epoch":1336608413}

那么如何建模filter和写view呢?

过滤器可能是这样的:

{"type":"filter", "location":["Seattle", "New York"], "start-epoch":1336608413}

那视图怎么写呢?

我想在 CouchDB 中实现这一点。我希望创建一个名为 FilteredSessions 的视图,并在对 Couch 的一次 http 调用中检索过滤后的会话。原因是因为我有 5 个不同的客户端(iOS、Android、Silverlight、Ruby on Rails 和 Windows 8),我不想重写逻辑 5 次。如果我使用 sqlite,我可以创建一个名为“FilteredView”的视图来实现这一点。我希望在 map reduce 中写出等价的东西。

【问题讨论】:

  • 对于具有多个任意字段的过滤器,您最好通过couchdb-lucene查看全文索引
  • @DominicBarnes 谢谢!我更新了我的问题以使其更清楚。一个过滤器仅适用于一个字段。例如。在上面的示例中,位置过滤器永远不会与 start-epoch 过滤器混合使用。
  • 那么,您是否尝试根据“过滤”文档生成视图/索引?
  • @DominicBarnes 是的。我的 Session 架构无法更改,但我尚未决定我的过滤器文档架构,因此它很灵活。
  • 您不能根据您的文档动态生成视图索引,并且不应在生产环境中使用“临时视图”。这些“过滤器”是您的用户生成的吗?如果是这样,您需要根据要过滤的字段创建一个 map/reduce 视图,并使用 _list 查询后处理根据一些查询字符串参数运行实际过滤器。

标签: database-design join view couchdb mapreduce


【解决方案1】:

嗯...我不确定您需要什么,但这是我的理解。您有一个数据集合,您正在调用会话,然后您有另一个数据集合,您正在调用过滤器。然后您想从会话中收集另一个数据集合,但使用过滤器数据从会话中选择特定数据。如果这是正确的,有几种方法可以做到这一点,这是一种:

假设您有 30 个左右的会话文档。它们各有两个属性:位置和起始时期。例如:

{
 "_id"         : "f80hqwfe8nfaodnia9dgs8n9",
 "location"    : "Seattle",
 "start-epoch" : "1336608413",
 "type"        : "session"
}

或者……

{
 "_id"         : "f8fsdnio345235aodnia9dgs8n9",
 "location"    : "New York",
 "start-epoch" : "1236630174",
 "type"        : "session"
}

然后你有一些过滤器,比如:

{
 "_id"         : "f80hqwfe8nfaodnia9dgs8n9",
 "location"    : "New York",
 "type"        : "filter"
}

或者……

{
 "_id"         : "f80hqwfe8nfaodnia9dgs8n9",
 "start-epoch" : "1336608413",
 "type"        : "filter"
}

您可以将所有会话拉到一个视图中:

"sesssions": {
  "map": "function (doc) {
    if (doc.type === "session") {
      emit(doc.start-epoch, doc);
    }
}"

然后,将所有过滤器拉到一个视图中(您可以即时更新):

"filters": {
  "map": "function (doc) {
    if (doc.type === "filter") {
      emit(doc.type, doc);
    }
}"

然后我将在 nodejs 中组装我的最终“视图”。如果需要,我会向我的数据库的过滤器视图发出请求或创建一个新过滤器,并将其存储在一个变量中,如过滤器或过滤器。然后我会再次调用我的数据库的会话视图,并将该数据拉入一个变量,如会话。

这里有一点旁注。您需要调用视图(假设您存储了沙发返回到 var 视图中的 json 对象),然后将 view.rows 存储到会话变量中,这将为您提供如下会话数组:

[
 {
  "_id"         : "f80hqwfe8nfaodnia9dgs8n9",
  "location"    : "Seattle",
  "start-epoch" : "1336608413",
  "type"        : "session"
 },
 {
  "_id"         : "f8fsdnio345235aodnia9dgs8n9",
  "location"    : "New York",
  "start-epoch" : "1236630174",
  "type"        : "session"
 }
]

那就做吧

var myFinalView = sessions.forEach(function (session) {
  if (filter.location !== session.location) {
    // session.splice or delete session
  }
  return;
})

然后 myFinalView 将是您需要的 JSON 对象。我希望这是有道理的。如果需要,请让我详细说明。

【讨论】:

  • 您几乎完全理解我的要求,只是我想在 CouchDB 中实现这一点。我希望创建一个名为 FilteredSessions 的视图,并在一次对 Couch 的 http 调用中检索过滤后的会话。原因是因为我有 5 个不同的客户端(iOS、Android、Silverlight、Ruby on Rails 和 Windows 8),我不想重写逻辑 5 次。如果我使用 sqlite,我可以创建一个名为“FilteredSessions”的视图来实现这一点。我希望在 NoSQL 中写出等价的东西。
  • 嗯...超级棘手。嗯,我有一点进展。让我把它贴出来看看是否有帮助。
【解决方案2】:
var sessions = [];
var filters = [];

function(doc) {
  if (doc.type === 'session') {
    sessions.push(doc);
  }
  if (doc.type === 'filter') {
    filters.push(doc);
  }
  emit(filters.length, filters);
  emit(sessions.length, sessions);
}

我试图将这些发射拉到函数末尾以下,但这似乎让 CouchDB 感到不安。这会将过滤器和会话“编译”成集合。如果有一种好方法可以知道“编译”何时完成,下一步将是遍历过滤器,然后 forEach 遍历应用过滤器的会话。

感谢分享这个挑战!这确实推动了 CouchDB 的极限。我希望我们能解决这个问题,这应该是可能的。

【讨论】:

    【解决方案3】:

    这是我的想法。在 map 函数中,发出会话和过滤文档。然后使用 list 函数枚举映射输出以读取持久化的过滤器和会话进行过滤。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多