2

我正在为我的应用程序实现过滤器功能,并且在 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}

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

过滤器可能是这样的:

{"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 中写出等价的东西。

4

3 回答 3

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 对象。我希望这是有道理的。如果需要,请让我详细说明。

于 2012-05-13T00:41:52.920 回答
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 感到不安。这会将过滤器和会话“编译”成集合。如果有一个好方法可以知道“编译”何时完成,下一步将是遍历过滤器,然后 forEach 遍历应用过滤器的会话。

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

于 2012-05-19T07:03:14.700 回答
0

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

于 2012-05-25T20:53:21.130 回答