Карта / Уменьшить различия между Couchbase и CloudAnt - PullRequest
2 голосов
/ 19 мая 2011

Я играл с Couchbase Server и сейчас только что попытался реплицировать мою локальную базу данных в Cloudant, но получаю противоречивые результаты для моей пары функций map / lower для создания набора уникальных тегов с соответствующими проектами ...

// map.js
function(doc) {
  if (doc.tags) {
    for(var t in doc.tags) {
      emit(doc.tags[t], doc._id);
    }
  }
}

// reduce.js
function(key,values,rereduce) {
  if (!rereduce) {
    var res=[];
    for(var v in values) {
      res.push(values[v]);
    }
    return res;
  } else {
    return values.length;
  }
}

На сервере Cloudbase это возвращает JSON как:

{"rows":[
{"key":"3d","value":["project1","project3","project8","project10"]},
{"key":"agents","value":["project2"]},
{"key":"fabrication","value":["project3","project5"]}
]}

Это именно то, что я хотел и ожидал.Однако тот же запрос к реплике Cloudant возвращает следующее:

{"rows":[
{"key":"3d","value":4},
{"key":"agents","value":1},
{"key":"fabrication","value":2}
]}

Так что он каким-то образом только возвращает длину массива значений ... Очень запутанно и благодарен за любые идеи некоторых ниндзя M & R ...;)

Ответы [ 2 ]

4 голосов
/ 19 мая 2011

Похоже, это именно то поведение, которое вы ожидаете, учитывая вашу функцию приведения. Ключевая часть такова:

else {
return values.length;
}

В Cloudant всегда вызывается rereduce (так как при сокращении необходимо охватить несколько сегментов.) В этом случае rereduce вызывает values.length, которое будет возвращать только длину массива.

2 голосов
/ 19 мая 2011

Я предпочитаю уменьшать / уменьшать неявно, а не в зависимости от параметра rereduce.

function(doc) { // map
  if (doc.tags) {
    for(var t in doc.tags) {
      emit(doc.tags[t], {id:doc._id, tag:doc.tags[t]});
    }
  }
}

Затем уменьшать проверяет, накапливает ли он идентификаторы документов из идентичного тега или он просто считает разные теги.

function(keys, vals, rereduce) {
  var initial_tag = vals[0].tag;

  return vals.reduce(function(state, val) {
    if(initial_tag && val.tag === initial_tag) {
      // Accumulate ids which produced this tag.
      var ids = state.ids;
      if(!ids)
        ids = [ state.id ]; // Build initial list from the state's id.
      return { tag: val.tag, 
             , ids: ids.concat([val.id])
             };
    } else {
      var state_count = state.ids ? state.ids.length : state;
      var val_count   = val.ids   ? val.ids.length   : val;
      return state_count + val_count;
    } 
  })
}

(Я не тестировал этот код, но вы поняли. Пока значение tag одинаково, оно не имеет значения, является ли это уменьшением или редукцией. Как только различные теги начинают сокращаться вместе, он обнаруживает это, потому что значение tag изменится. Так что в этот момент просто начинайте накапливаться.

Я использовалэтот трюк раньше, хотя IMO редко стоит.

Также в в вашем конкретном случае , это опасная функция сокращения. Вы строите широкий список, чтобы увидеть все документы, которые имеюттег. CouchDB любит высокие списки, а не толстые списки. Если вы хотите увидеть все документы, которые имеют тег, вы можете отобразить их.

for(var a = 0; a < doc.tags.length; a++) {
  emit(doc.tags[a], doc._id);
}

Теперь вы можете запросить /db/_design/app/_view/docs_by_tag?key="3d", и вы должны получить

{"total_rows":287,"offset":30,"rows":[
{"id":"project1","key":"3d","value":"project1"}
{"id":"project3","key":"3d","value":"project3"}
{"id":"project8","key":"3d","value":"project8"}
{"id":"project10","key":"3d","value":"project10"}
]}
...