我正在为我的应用程序实现过滤器功能,但在 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 函数枚举映射输出以读取持久化的筛选器和会话以执行筛选。