0
votes

I've got a database of messages between users. Document looks like:

"_id": "msg_0bec56c1-cbfb-47a5-8882-4a61fec332cd",
"_rev": "1-00000eda4d07c93d0000009100000112",
"$flags": 0,
"$expiration": 0,
"Date": 1340280439303,
"OwnerId": 35,
"RcptId": 37,
"SndrId": 35,
"Text": "msg5",
"Unread": false,
"id": "0bec56c1-cbfb-47a5-8882-4a61fec332cd",
"type": "msg"

For each message it stores 2 documents with different OwnerId. I need to get the lastest message between one specified person and 10 uniqe "pen friends" ordered by last message date.

My query params:

descending=true&endkey=[35,35]&startkey=[35,35,"{}"]&limit=10&skip=0

My map function:

function (doc) {
   if (doc.type == "msg"){
     emit([doc.OwnerId, doc.SndrId, doc.Date, doc.RcptId], doc);
     emit([doc.OwnerId, doc.RcptId, doc.Date, doc.SndrId], doc);
   }
}

As a result I get list of messages for desired account. Last value (4th) in key is that value on which we should group values.

Groupping with group level 4 not working because dates are different.

1
I've created reduce function that produces results I need. But I cant't apply limit=10 to it. function(keys,values,rereduce){ var usrs = {}; var res = []; var i=0; keys.forEach(function(key) { if (!usrs[key[0][3]]){ usrs[key[0][3]] = true; res.push(values[i]); } i=i+1; }); return res; //return values; } - m03geek

1 Answers

0
votes

Here is my new map function that does exactly what i've wanted BUT only if I have one server.

var uniqPairs = [];
function(doc){
  if (doc.type == "msg"){
    if (doc.OwnerId == doc.SndrId){
      if (uniqPairs.indexOf(doc.OwnerId + "_" + doc.RcptId) == -1){
        uniqPairs.push(doc.SndrId + "_" + doc.RcptId);
        uniqPairs.push(doc.RcptId + "_" + doc.SndrId);
        emit([doc.OwnerId, doc.Date], {"owner": doc.OwnerId, "from":doc.SndrId, "to":doc.RcptId});
      }
    }
    if (doc.OwnerId == doc.RcptId){
      if (uniqPairs.indexOf(doc.OwnerId + "_" + doc.SndrId) == -1){
        //uniqPairs.push(doc.SndrId + "_" + doc.RcptId);
        uniqPairs.push(doc.RcptId + "_" + doc.SndrId);
        emit([doc.OwnerId, doc.Date], {"owner": doc.OwnerId, "from":doc.SndrId, "to":doc.RcptId});
      }
    }
  }
}

So for cluster I sacrificed "ordering by date" and got such functions for map/reduce:

Map:

function (doc) {
  if (doc.type == "msg"){
    if (doc.OwnerId == doc.SndrId){
      emit([doc.OwnerId, doc.RcptId, doc.Date], {"Date":doc.Date, "OwnerId":doc.OwnerId, "RcptId":doc.RcptId, "SndrId":doc.SndrId, "Text":doc.Text, "Unread":doc.Unread, "id": doc.id, "type":doc.type});
    } else {
      emit([doc.OwnerId, doc.SndrId, doc.Date], {"Date":doc.Date, "OwnerId":doc.OwnerId, "RcptId":doc.RcptId, "SndrId":doc.SndrId, "Text":doc.Text, "Unread":doc.Unread, "id": doc.id, "type":doc.type});
    }
  }
}

Reduce:

var tmp = [];
var t = [];
function findRecent(arr){
  var max = 0;
  var maxId = 0;
  for (var i in arr){
    if (arr[i].Date > max){
      max = arr[i].Date;
      maxId = i;
    }
  }
  return arr[maxId];
}
function(k,v,r){
  if (!r){
    tmp.push(v);
  }
  else{
    tmp.push(v);
  }
  if (r){
    for (var i1 in tmp[0])
    {  
        t.push(tmp[0][i1]);
    }
  } else {
     return findRecent(v);
  }
  return findRecent(t);
}

If someone knows better solution (i.e. how to oreder results by date) - you're welcome to answer.