将 SQL 中的多个联接替换为 CouchDB 视图



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

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

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

在SQL中,我有两个表:会话和过滤器。 然后,我在会话和过滤器表之间的每个过滤条件都有一个联接,以获取所有过滤的会话。

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"的视图来实现这一点。 我希望在mapreduce中写等效的。

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

假设您有 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中组装我的最终"视图"。如果需要,我会向数据库的过滤器视图发出请求或创建一个新过滤器,并将其存储在变量中,例如过滤器或过滤器。 然后,我会再次调用数据库的会话视图,并将该数据拉取到变量中,例如会话。

这里有一点旁注。 您需要调用视图(假设您存储了 couch 返回到 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对象。 我希望这是有道理的。 如果需要,请让我详细说明。

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上突破了极限。我希望我们能弄清楚这一点,这应该是可能的。

这是我

的想法。 在映射函数中,同时发出会话和筛选器文档。 然后使用 list 函数枚举映射输出以读取持久化的筛选器和会话以执行筛选。

相关内容

  • 没有找到相关文章

最新更新