Можем ли мы отсортировать отсортированный список в CouchDb?
У меня есть 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);}}
}
Мое беспокойство: есть ли способ отсортировать события сначала по расстоянию в списке, а затем обработать отсортированный список по времени начала?
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
но так как первый более ранний, он сортируется первым.
Надеюсь, это поможет!