【问题标题】:Can we sort a sorted list view in CouchDb?我们可以在 CouchDb 中对排序的列表视图进行排序吗?
【发布时间】:2012-08-12 03:21:15
【问题描述】:

我有一个 couchdb,其中包含事件及其开始时间和坐标。我写了一个列表视图来计算从您当前位置到这些事件的距离,如下所示:

locateEvents: function(head, req){ 

        var row, comma = ''; 
        start({
            "headers": {
                "Content-Type": "application/json"
            }
        });
        if(req.query.latitude&&req.query.longitude&&req.query.radius&&req.query.now){

            var R = 6371; // km
            var dLon, dLat, lat1, lat2;

            var results = [];
            while(row = getRow()) { 
                dLon = Math.abs(row.value.venue.longitude-req.query.longitude);
                dLat = Math.abs(row.value.venue.latitude-req.query.latitude);

                dLon = (dLon*3.14159)/180;
                dLat = (dLat*3.14159)/180;

                lat1 = (Math.abs(req.query.longitude)*3.14159)/180;
                lat2 = (Math.abs(req.query.latitude)*3.14159)/180;

                var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); 
                var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
                var d = R * c;

                if((d < req.query.radius)&&(row.value.start_time > req.query.now)){
                    results.push(row.value);
                }
            }
            send(JSON.stringify(results));
        }else{
            start({"code": 500});
            send("Latitude, longitude, page and radius parameters should be provided. i.e: latitude=value&longitude=value&radius=value&now=value");
        }

我有一个简单的 byDate 事件视图,如下所示:

byDate: {
            map: function(doc){ if (doc.resource === 'Event') {emit(doc.venue.start_time, doc);}}
        }

我的担忧:有没有办法先按列表中的距离对事件进行排序,然后按开始时间对排序后的列表进行排序?

【问题讨论】:

    标签: javascript couchdb couchdb-futon


    【解决方案1】:

    如果我理解正确,您希望最接近的事件首先出现。如果在同一距离内有两个事件,则先显示最早的事件。

    这可以通过在将对象推送到结果集之前保存计算出的距离来完成:

    row.value._distance = d;
    results.push(row);
    

    请注意,您现在无法保存文档,因为以下划线 _ 开头的所有字段都由 couchdb 保留。但是由于每个请求到事件的距离可能不同,这很好。如果您需要将文档保存回商店,请记住删除该属性。

    在下一步中,我们需要想出一种巧妙的方法来对您的事件进行排序 - 我们需要的所有信息现在都存储在文档中。

    由于 JavaScript 不喜欢对复杂的数据结构进行排序,我们必须做一些跑腿工作:

    var sort = function(a,b) {
      if (JSON.stringify(a) == JSON.stringify(b)) return 0;
      return (JSON.stringify([a,b]) == JSON.stringify([a,b].sort())) ? -1 : 1
    };
    

    这个函数只是对一个简单值的数组进行排序,如下所示:

    > sort(["a",1], ["a", 0])
    1
    
    > sort(["a",0], ["a", 1])
    -1
    
    > sort(["a",0], ["a", 0])
    0
    

    现在是有趣的部分,在您 send 将结果返回给客户端之前,您对它们进行排序:

    // ...
    results.sort(function(a, b) {
      return sort(
        [a.value._distance, a.value.venue.start_time],
        [b.value._distance, b.value.venue.start_time]
      );
    });
    
    send(JSON.stringify(results));
    

    例子:

    [{"value": {"_distance": 100, "venue": { "start_time": "Wed, 21 Mar 2012 04:31:24 -0700" } } },
     {"value": {"_distance": 212, "venue": { "start_time": "Sat, 13 Oct 2012 02:52:12 -0700" } } },
     {"value": {"_distance": 235, "venue": { "start_time": "Mon, 22 Jul 2013 12:50:20 -0700" } } },
     {"value": {"_distance": 677, "venue": { "start_time": "Thu, 09 May 2013 03:39:55 -0700" } } },
     {"value": {"_distance": 654, "venue": { "start_time": "Thu, 29 Sep 2011 15:31:46 -0700" } } },
     {"value": {"_distance": 100, "venue": { "start_time": "Tue, 20 Sep 2011 19:16:37 -0700" } } }]
    

    使用上面的sort函数后变成这个:

    [{"value": {"_distance": 100, "venue": {"start_time": "Tue, 20 Sep 2011 19:16:37 -0700" } } },
     {"value": {"_distance": 100, "venue": {"start_time": "Wed, 21 Mar 2012 04:31:24 -0700" } } },
     {"value": {"_distance": 212, "venue": {"start_time": "Sat, 13 Oct 2012 02:52:12 -0700" } } },
     {"value": {"_distance": 235, "venue": {"start_time": "Mon, 22 Jul 2013 12:50:20 -0700" } } },
     {"value": {"_distance": 654, "venue": {"start_time": "Thu, 29 Sep 2011 15:31:46 -0700" } } },
     {"value": {"_distance": 677, "venue": {"start_time": "Thu, 09 May 2013 03:39:55 -0700" } } }]
    

    注意排序后,前两个对象有_distance == 100,但由于第一个更早,所以先排序。

    希望有帮助!

    【讨论】:

    • 这看起来很有希望...我在进行更改时收到此错误:Log :: function raised error: (new TypeError("a.value is undefined", "", 40))
    • 啊 nvm 我正在推动 row.value 而不仅仅是 row
    • 好吧,这很好用,我不知道当我获得数百万个事件时这会有多高效,但它现在可以完成工作。
    • 您可以随时限制radius 参数的值,从而减少视图返回的事件数。如果负载变得太大,CouchDB Guide suggests 使用像 Squid 这样的缓存反向代理。尽管这不会有太大帮助,因为地理查询通常是高度动态的并且不经常重复。如果您真的很重视性能,请查看geocouch
    猜你喜欢
    • 1970-01-01
    • 2014-06-21
    • 1970-01-01
    • 2010-09-05
    • 2018-07-08
    • 2019-09-19
    • 2018-10-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多