用CouchDB视图替换SQL中的多个连接

时间:2012-05-10 00:29:07

标签: database-design join view couchdb mapreduce

我正在为我的应用程序实现一个过滤器功能,并且无法在CouchDB上编写视图。在SQL中,这将是一个多连接的语句。如何在CouchDB中替换多个连接。本文介绍了单一联接:http://www.cmlenz.net/archives/2007/10/couchdb-joins。但是,对于我来说,如何将此方法扩展到多个连接并不明显。

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

我的应用程序需要支持一堆AND过滤器。例如。找到位于(“西雅图”,“纽约”)AND start-epoch> = 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}

那么如何建模过滤器并编写视图?

过滤器可能是这样的:

{"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中写出等效的缩写。

3 个答案:

答案 0 :(得分:1)

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

假设您有30个左右的会话文档。它们各有两个属性:location和start-epoch。例如:

{
 "_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存储到sessions变量中,这将为您提供如下所示的会话数组:

[
 {
  "_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对象。我希望这是有道理的。请让我详细说明是否需要。

答案 1 :(得分:0)

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感到不安。这会将过滤器和会话“编译”到集合中。如果有一种很好的方法可以知道“编译”何时完成,那么下一步就是遍历过滤器,然后通过应用过滤器的会话进行每次循环。

感谢您分享这一挑战!这个真的推动了CouchDB的发展。我希望我们能够弄清楚这一点,应该是可能的。

答案 2 :(得分:0)

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