コード例 #1
0
ファイル: index.js プロジェクト: skydom-io/jflo-analyze
/**
 * Flattens a pojs object, prepends every component path with key
 * @param key
 * @param value
 */
function flatten(prefix_path, value, options) {

    var flattened;
    var delimiter = (options || {}).delimiter || PATH_DELIMITER;
        prefix_path = prefix_path.split(delimiter).filter(function (part) {
            return part.length > 0
        }).join(PATH_DELIMITER);
    if ((prefix_path || "").length) {
        var obj = {};
        obj[prefix_path] = value;
        flattened = flat.flatten(obj, {delimiter: delimiter});
    }
    else {
        flattened = flat.flatten(value, {delimiter: delimiter});
    }

    if (options.container_paths) {
        // Add container entries - key: {} or key: []
        _flattenContainers(value, prefix_path, flattened);
    }
    return flattened;

    function _flattenContainers(obj, curpath, flat) {
        if (Object(obj) !== obj) {
            return;
        }
        flat[curpath] = Array.isArray(obj) ? [] : {};
        for (var key in obj) {
            _flattenContainers(obj[key], (curpath.length ? curpath + delimiter : "") + key, flat)
        }
    }
}
コード例 #2
0
ファイル: index.js プロジェクト: nswbmw/node-nana
NANA.prototype.match = function match(pattern, modifiers) {
  if (!this.flag) return this;

  if (_.isObject(this._curArgs)) {
    var _flatCurArgs = flat.flatten(this._curArgs);
    var _flatCompArgs = flat.flatten(pattern);
    // console.log(_flatCurArgs);
    // console.log(_flatCompArgs);
    // console.log(this._curArgs)
    if (_.keys(_flatCurArgs).length !== _.keys(_flatCompArgs).length) {
      this.flag = false;
      return this;
    }
    for (var key in _flatCurArgs) {
      if (key in _flatCompArgs) {
        if (!this.flag) return this;
        if (!_.isString(validator.toString(_flatCurArgs[key]))) {
          this.flag = false;
          return this;
        }
        // console.log(key)
        // console.log(_flatCurArgs[key])
        // console.log(_flatCompArgs[key])
        this.flag = validator.matches(_flatCurArgs[key], _flatCompArgs[key]);
      } else {
        this.flag = false;
        return this;
      }
    }
    return this;
  }

  if (_.isArray(this._curArgs)) {
    this.flag = this.match(flat.flatten(this._curArgs));
    return this;
  }

  if (_.isString(this._curArgs)) {
    this.flag = validator.matches(this._curArgs, pattern, modifiers);
    return this;
  }

  try {
    this.flag = validator.matches(validator.toString(this._curArgs), pattern, modifiers);
  } catch(e) {
    this.flag = false;
  }
  return this;
};
コード例 #3
0
ファイル: index.js プロジェクト: nswbmw/koa-scheme
      matchArr.forEach(function (expect) {
        var flat_conf_response = expect.response || {};
        var flat_ctx_response = flatten(filterFunc(ctx.response), {safe: true});

        Object.keys(flat_conf_response).forEach(function (key) {
          if ('function' === typeof flat_conf_response[key]) {
            try {
              if (!flat_conf_response[key].call(ctx, flat_ctx_response[key])) {
                if (options.debug) ctx.throw(500, JSON.stringify(flat_ctx_response[key]) + ' ✖ [Function: ' + (flat_conf_response[key].name || 'function') + ']');
              }
            } catch (e) {
              debug('%s %s -> %s : %s', ctx.method, ctx.path, key, e.message);
              ctx.throw(e.statusCode || e.status || 500, e.message);
            }
          } else {
            if (flat_ctx_response[key] === undefined) {
              debug('%s %s -> %s', ctx.method, ctx.path, key + ' : Not exist!');
              ctx.throw(500, key + ' : Not exist!');
            }
            if (!RegExp(flat_conf_response[key]).test(flat_ctx_response[key])) {
              debug('%s %s -> %s : %j ✖ %j', ctx.method, ctx.path, key, flat_ctx_response[key], flat_conf_response[key]);
              ctx.throw(500, key + ' : ' + flat_ctx_response[key] + ' ✖ ' + flat_conf_response[key]);
            }
          }
        });
      });
コード例 #4
0
ファイル: SchemaTools.js プロジェクト: KathyReid/schemas
Schemas.prototype.getEventTimeSeriesData = function(value, eventSchemaUri) {

  var timeseriesData = [];

  var eventSchema = this.getSchema(eventSchemaUri);

  log.trace('Finding time series data for event', eventSchemaUri, 'from payload', value);

  if (!eventSchema) {
    throw new Error('No schema found for uri "' + eventSchemaUri + '"');
  }

  if (eventSchema.value) {
    if (typeof value == 'object') {
      // The payload may have nested properties that need to be stored... so we need to look though the whole tree.
      var flat = flatten(value);

      Object.keys(flat).forEach(function(path) {
        timeseriesData.push(this._getPathTimeSeriesData(flat[path], path, eventSchemaUri + '/value'));
      }.bind(this));

    } else {
      // The payload is a 'simple' value.
      timeseriesData.push(this._getPathTimeSeriesData(value, null, eventSchemaUri + '/value'));
    }
  }

  // If the event itself has timeseries="event", we store it as an event
  timeseriesData.push(this._getPathTimeSeriesData(null, null, eventSchemaUri));

  return timeseriesData.filter(function(v) {return !!v;});
};
コード例 #5
0
InfluxDB.prototype.write = function(metric, fn){
    var metric = flat.flatten(metric);
    _.each(metric, function(val, key){
        if(!_.isObject(val))
            this.client.writePoint(key, { value: val, time: new Date() }, null, {}, function(err, response){});
    }, this);
}
コード例 #6
0
ファイル: JSONRPCServer.js プロジェクト: AeroGirl/usvc
    exportedFacets.map(function(facet) {
      var flattened = flat.flatten(facet.rpc_methods);

      for (var name in flattened) {
        methods[facet.name + '.' + name] = flattened[name].bind(facet);
      }
    }.bind(this));
コード例 #7
0
            self.db.get(sid, function (err, doc) {
                if (err) {
                    debug('Session was not found from couchdb, or error occurred', sid);
                    doc = {
                        _id: sid,
                        expires: expires,
                        type: 'connect-session',
                        sess: sess
                    };
                    doc = flat.flatten(doc, {safe: true});
                    self.db.save(doc, function(err) {
                        if(err) return fn(new Error(err));
                        return fn();
                    });
                } else {
                    doc = flat.unflatten(doc, {safe: true});
                    var accessGap = sess.lastAccess - doc.sess.lastAccess;
                    var differencies = diff(doc.sess, sess);

                    differencies = _.filter(differencies, function(d) {
                        var path = d.path.join('.');
                        return ['lastAccess', 'cookie.originalMaxAge', 'cookie._expires', 'cookie.expires', '__connect_couchdb_cache'].indexOf(path) === -1;
                    });
                    // Compare new session to current session, save if different
                    // or setThrottle elapses
                    debug('Differencies from last save: ', differencies);
                    debug('accessGap bigger than setThrottle: ', accessGap > this.setThrottle);
                    var savedSessString = JSON.stringify(doc.sess),
                        currentSessString = JSON.stringify(sess);
                    if (differencies.length || accessGap > this.setThrottle) {
                        doc.expires = expires;
                        doc.sess = sess;
                        debug('Saving session: ', doc.sess);
                        doc = flat.flatten(doc, {safe: true});
                        this.db.save(doc, function(err) {
                            if (err && savedSessString !== currentSessString) {
                                console.error(savedSessString +'!='+ currentSessString);
                                return fn(new Error(err));
                            }
                            return fn();
                        });
                    } else {
                        return fn();
                    }
                }
            }.bind(self));
コード例 #8
0
ファイル: messages.js プロジェクト: nitrogenjs/core
var flatten = function(message, opt) {
    var options = {
        safe : true,
        delimiter: '__'
    };

    for (var attrname in opt) { options[attrname] = opt[attrname]; }

    return flat.flatten(message, options);
};
コード例 #9
0
ファイル: bracketer.js プロジェクト: suisho/example-hyotens
export default function(input){
  var data = flatten(input)
    var item = Immutable.Map(data).flatMap((value, key) => {
      return Immutable.Map().set(
        toBlacketKey(key), value
      )
    }
  )
  return item.toJS()
}
コード例 #10
0
ファイル: parser.js プロジェクト: zhouanbo/pipelinedog-cli
 Object.keys(rObj).map((key, index) => {
   if (index === Object.keys(rObj).length-1) {
     Object.keys(rObj[key]).map(stepKey => {
       varObj[stepKey] = rObj[key][stepKey]
     })      
     let flatStepObj = flatten(rObj[key], {safe: true})
     Object.keys(flatStepObj).map(stepKey => {
         varObj[stepKey] = flatStepObj[stepKey]
     })
   } else {
     gvarObj[key] = rObj[key]
   }
 })
コード例 #11
0
                    var matching_hosts = _.filter(peers, function(peer){
                        var tags = flat.flatten(peer.tags);

                        var tag_name = firewall.source.split("=")[0];
                        var tag_value = firewall.source.split("=")[1];

                        if((_.has(tags, tag_name) && tags[tag_name] == tag_value) || firewall.source == "*"){
                            _.each(_.keys(peer.address), function(scope){
                                var rule_copy = _.clone(rule);
                                rule_copy.source = peer.address[scope]
                                rules.push(rule_copy);
                            });
                        }
                    });
コード例 #12
0
ファイル: tool-stream.js プロジェクト: bmpvieira/tool-stream
 function cb(obj, enc, next) {
   var flatObj = flat.flatten(obj)
   var relevantData = []
   Object.keys(flatObj).forEach(checkRelevant)
   function checkRelevant(key) {
     var value = flatObj[key].toString()
     if (value.match(regex)) {
       relevantData.push(value)
     }
   }
   uniqueRelevantData = relevantData.filter(function(elem, pos, self) {
     return self.indexOf(elem) == pos;
   })
   obj[propertyToSave] = uniqueRelevantData
   this.push(obj)
   next()
 }
コード例 #13
0
ファイル: labels.js プロジェクト: dannydavidson/s195-graph
	index = ( function ( config ) {
		var index,
			flattened = flat.flatten( config, {
				delimiter: LABEL_DELIMITER
			} );

		index = _( flattened ).chain().map( function ( val, key ) {
			return [ _.last( key.split( LABEL_DELIMITER ) ), LABEL_DELIMITER + key ];
		} ).object().value();


		index.schools = ':schools';
		index.geographies = ':geographies';

		return index;

	} )( config );
コード例 #14
0
ファイル: index.js プロジェクト: nswbmw/node-nana
NANA.prototype.hasnt = function hasnt(arr) {
  if (!this.flag) return this;

  if (!_.isArray(arr) || arguments.length > 1) {
    return this.hasnt(_.toArray(arguments));
  }

  if (_.isArray(this._curArgs)) {
    var _obj = flat.flatten(arr);
    this.flag = !_.has.apply(null, [_obj].concat(arr));
  } else if (_.isObject(this._curArgs)) {
    this.flag = !_.has.apply(null, [this._curArgs].concat(arr));
  } else {
    this.flag = true;
  }

  return this;
};
コード例 #15
0
ファイル: replace.js プロジェクト: NicolasBru/grunt-replace
 patterns.forEach(function (pattern) {
   var json = pattern.json;
   if (typeof json !== "undefined") {
     // json
     if (_.isObject(json)) {
       _.forOwn(flatten(json), function(value, key) {
         registerPattern({
           match: key,
           replacement: value
         });
       });
     } else {
       grunt.fail.fatal('Unsupported type for json (Object expected).');
       return;
     }
   } else {
     // match
     registerPattern(pattern);
   }
 });
コード例 #16
0
ファイル: express.js プロジェクト: hkjels/old-effor
module.exports = function (app) {

  // Flatten the preferences for use with `app.set`,

  preferences = flatten(preferences, { delimiter: ' ' });

  // General

  app.configure(function () {
    for (var key in preferences) {
      if (!preferences.hasOwnProperty(key)) continue;
      app.set(key, preferences[key]);
    }
    app.set('port', process.env.PORT || 3000);
    app.set('root', normalize(__dirname + '/../'));
    app.set('views', normalize(app.get('root') + 'views'));
    app.set('view engine', 'jade');
    app.use(express.favicon());
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser(app.get('salt')));
    app.use(express.session());
    app.disable('verbose');
  });

  // Development server

  app.configure('development', function () {
    app.use(express.logger('dev'));
    app.use(express.errorHandler());
    app.enable('verbose');
  });

  // Ensure that tests do not manipulate the dev-db

  app.configure('test', function () {
    app.set('db collection', 'effor-test');
  });
}
コード例 #17
0
ファイル: redis.js プロジェクト: pchaussalet/dockmon_server
exports.saveValues = function(key, values) {
    return db.hmset(key, flat.flatten(values));
};
コード例 #18
0
ファイル: index.js プロジェクト: ZhangXinmiao/koaTest
  return function* (next) {
    var ctx = this;
    var _conf;
    var _method;
    var _path;

    var _keys = Object.keys(conf);
    for (var i = 0; i < _keys.length; i++) {
      var path = _keys[i];
      var _arr = path.split(' ');
      // compatible with v0.2.0
      if (_arr.length === 1) {
        if (pathToRegexp(_arr[0]).test(ctx.path)) {
          if (!conf[path].request ||
            !conf[path].request.method ||
            RegExp(conf[path].request.method, "i").test(ctx.method)) {
            _conf = conf[path];
            _method = ctx.method;
            _path = ctx.path;

            debug('%s %s -> %s', _method, _path, path);
            break;
          }
        }
      } else if (_arr.length === 2) {
        if (pathToRegexp(_arr[1]).test(ctx.path)) {
          if (RegExp(_arr[0], "i").test(ctx.method)) {
            _conf = conf[path];
            _method = ctx.method;
            _path = ctx.path;

            debug('%s %s -> %s', _method, _path, path);
            break;
          }
        }
      }
    };

    if (_conf) {
      flat_conf_request = flatten(_conf.request || {});
      flat_ctx_request = flatten(filterFunc(ctx.request) || {}, {safe: true});

      Object.keys(flat_conf_request).forEach(function (key) {
        if (flat_ctx_request[key] === undefined) {
          debug('%s %s -> %s', _method, _path, key + ' : Not exist!');
          ctx.throw(400, _method + ' ' + _path + ' -> ' + key + ' : Not exist!');
        }
        if (typeof flat_conf_request[key] === 'function') {
          if(!flat_conf_request[key](flat_ctx_request[key])) {
            ctx.throw(400, _method + ' ' + _path + ' -> ' + key + ' : ' + flat_ctx_request[key] + ' ✖ ' + '[Function: ' + (flat_conf_request[key].name || 'function') + ']');
          }
        } else {
          if (!RegExp(flat_conf_request[key]).test(flat_ctx_request[key])) {
            debug('%s %s -> %s : %s ✖ %s', _method, _path, key, flat_ctx_request[key], flat_conf_request[key]);
            ctx.throw(400, _method + ' ' + _path + ' -> ' + key + ' : ' + flat_ctx_request[key] + ' ✖ ' + flat_conf_request[key]);
          }
        }
      });

      yield* next;

      flat_conf_response = flatten(_conf.response || {});
      flat_ctx_response = flatten(filterFunc(ctx.response) || {}, {safe: true});

      Object.keys(flat_conf_response).forEach(function (key) {
        if (flat_ctx_response[key] === undefined) {
          debug('%s %s <- %s', _method, _path, key + ' : Not exist!');
          ctx.throw(500, _method + ' ' + _path + ' <- ' + key + ' : Not exist!');
        }
        if (typeof flat_conf_response[key] === 'function') {
          if(!flat_conf_response[key](flat_ctx_response[key])) {
            ctx.throw(500, _method + ' ' + _path + ' <- ' + key + ' : ' + flat_ctx_response[key] + ' ✖ ' + '[Function: ' + (flat_conf_response[key].name || 'function') + ']');
          }
        } else {
          if (!RegExp(flat_conf_response[key]).test(flat_ctx_response[key])) {
            debug('%s %s <- %s : %s ✖ %s', _method, _path, key, flat_ctx_response[key], flat_conf_response[key]);
            ctx.throw(500, _method + ' ' + _path + ' <- ' + key + ' : ' + flat_ctx_response[key] + ' ✖ ' + flat_conf_response[key]);
          }
        }
      });
    }
  }
コード例 #19
0
ファイル: index.js プロジェクト: nswbmw/koa-scheme
 Object.keys(_conf).forEach(function (path) {
   if (_conf[path].request) _conf[path].request = flatten(_conf[path].request, {safe: true});
   if (_conf[path].response) _conf[path].response = flatten(_conf[path].response, {safe: true});
 });
コード例 #20
0
ファイル: mongo.js プロジェクト: DRI-Dev/dricode
exports.madd = madd = function madd(entityToAddIn, command, callback) {
    (command && command.db) ? databaseToLookup = command.db : databaseToLookup;
    (command && command.databasetable) ? mongoDatabaseToLookup = command.databasetable : mongoDatabaseToLookup;
    (command && command.collection) ? schemaToLookup = command.collection : schemaToLookup;

    // console.log('>>>> entity added is ' + JSON.stringify(entityToAddIn));
    // console.log('>>>>databaseToLookup >>> ' + databaseToLookup);

    var entityToAdd = entityToAddIn;
    var entityToUpdate = entityToAddIn;
    console.log('>>>>entityToAdd >>> ' + JSON.stringify(entityToAdd));

    var addOptions = {};

    var widVal = (entityToAdd['wid']);


    widVal = {
        "wid": widVal
    };

    addOptions = {};
    console.log(" :: DAO :: command.datamethod -- "+JSON.stringify(command));
    console.log(" :: DAO :: command.datamethod -- "+command.datamethod);
    if (command && command.datamethod === 'clear') {
        // clear
        // clear saves the new came object after clearing the existing object
        // clear cleared the whole aid --all databases
        objToUpdate = entityToAdd;
        addOptions = {};
    } else if (command && command.datamethod === 'insert') {
        // insert
        // insert cleraeted only the db being used
        objToUpdate = {
            "$set": entityToAdd
        };
    } else {
        // upsert
        // upsert saves the new came object after updating the existing object
        // upsert -- default
        entityToUpdate = flatten(entityToAdd, {
            safe: true
        });

        addOptions = {
            "upsert": true
        };

    }


    mget(widVal, command, function(err, returnedObject) {
        // check if object is found
        if (returnedObject) {
            mupdate(widVal, {
                "$set": entityToUpdate
            }, command, addOptions, function(err, res) {
                if (err) {
                    console.log('DAO :: madd :: error in updating -- ' + err);
                    callback(err, {
                        etstatus: {
                            status: "updateerrror"
                        }
                    });
                } else {
                    mget(widVal, command, function(err, res) {
                        if (err) {
                            console.log('DAO :: madd :: error in getting post update -- ' + err);
                            callback(err, {
                                etstatus: {
                                    status: "geterror"
                                }
                            });
                        } else {
                            console.log(res);
                            callback(err, res);
                        }
                    });
                }
            });
        } else {
            maddnew(entityToAdd, command, function(err, res) {
                if (err) {
                    console.log('DAO :: madd :: error in adding -- ' +err);
                    callback(err, {
                        etstatus: {
                            status: "adderrror"
                        }
                    });
                } else {
                    callback(err, res);
                }
            });
        }
    });
};
コード例 #21
0
ファイル: parser.js プロジェクト: zhouanbo/pipelinedog-cli
  replaceVars(rawObj) {
    let varObj = {}
    let gvarObj = {}
    let rObj = rawObj

    let flatObj = flatten(rObj, {safe: true})
     
    //change numbers to strings
    Object.keys(flatObj).map(key => {
      if (typeof(flatObj[key]) === 'number') flatObj[key] = flatObj[key].toString()
    })

    //get vars
    Object.keys(rObj).map((key, index) => {
      if (index === Object.keys(rObj).length-1) {
        Object.keys(rObj[key]).map(stepKey => {
          varObj[stepKey] = rObj[key][stepKey]
        })      
        let flatStepObj = flatten(rObj[key], {safe: true})
        Object.keys(flatStepObj).map(stepKey => {
            varObj[stepKey] = flatStepObj[stepKey]
        })
      } else {
        gvarObj[key] = rObj[key]
      }
    })

    let flatVarObj = Object.assign(varObj, flatten(gvarObj, {safe: true}))

    //switch vars in a string
    const processValue = (value) => {
      if (typeof(value) === 'string') {
        //sort to make sure the longer vars get recognized first
        Object.keys(flatVarObj).sort((a, b)=>{return b.length-a.length}).map((processKey) => { 
          let pos = typeof(value) === 'string' ? value.indexOf('$'+processKey, pos + 1) : -1
          while (pos !== -1) {
            if (typeof(flatVarObj[processKey]) === 'string') {
              value = value.replace('$'+processKey, flatVarObj[processKey])
            } else {
              value = flatVarObj[processKey]
            }
            pos = typeof(value) === 'string' ? value.indexOf('$'+processKey, pos + 1) : -1
          }      
        })
        return value
      }
    }

    //replace keys
    Object.keys(flatObj).map(key => {
      let processedKey = processValue(key)
      if (processedKey !== key) {
        flatObj[processedKey] = flatObj[key]
        delete flatObj[key]
      }
    })
    //replace values
    const haveVar = () => {
      let rKey = false
      Object.keys(flatObj).map(key => {
        Object.keys(flatVarObj).map(varKey => { 
          if (flatObj[key] && typeof(flatObj[key]) === 'string' && flatObj[key].indexOf('$'+varKey) > -1 && key.indexOf("comment") === -1) {
            rKey = key
          }
        })
      })
      return rKey
    }
    let varKey
    while (varKey = haveVar()) {
      flatObj[varKey] = processValue(flatObj[varKey])
    }

    rObj = unflatten(flatObj)
    //remove var definitions
    let rObjKeys = Object.keys(rObj)
    rObjKeys.map((key, index) => {
      if (index !== rObjKeys.length-1) {
        delete rObj[key]
      }
    })

    return rObj
  }
コード例 #22
0
ファイル: Flatten.js プロジェクト: guidesmiths/prepper
 this.handle = function(event) {
     self.emit('message', flatten(event))
 }
コード例 #23
0
 flatten: function (target, opts) {
   if (opts != null && opts.safe == null) {
     opts.safe = true;
   }
   return flat.flatten(target, opts);
 },
コード例 #24
0
ファイル: autocomplete.js プロジェクト: dready92/mupee
 var values = result.map(function(value) {
   return flatten(value)[property];
 });
コード例 #25
0
    function saveToCouch(self, sid, sess, fn) {
        var expires = typeof sess.cookie.maxAge === 'number' ?
            (+new Date()) + sess.cookie.maxAge
            : (+new Date()) + (24 * 60 * 60 * 1000);
        var cached;
        if(sess.__connect_couchdb_cache && (cached = cache.get(sess.__connect_couchdb_cache))) {
            var cacheId = sess.__connect_couchdb_cache;
            delete sess.__connect_couchdb_cache;
            debug('Found cached session, calculating diff', cacheId);
            var merge = {},
                accessGap = sess.lastAccess - cached.lastAccess,
                differencies = _.filter(diff(cached, sess), function(d) {
                    var path = d.path.join('.');
                    return ['lastAccess', 'cookie.originalMaxAge', 'cookie._expires', 'cookie.expires'].indexOf(path) === -1;
                });
            cache.del(cacheId);     //delete cache item, it's not needed anymore
            if (differencies.length || accessGap > self.setThrottle) {
                _.each(differencies, function (d) {
                    if(d.kind === 'D') {
                        var it = merge, i, u;
                        u = d.path.length - 1;
                        for(i = 0; i < u; i++){
                            if (typeof it[d.path[i]] === 'undefined') {
                                it[d.path[i]] = {};
                            }
                            it = it[d.path[i]];
                        }
                        it[d.path[d.path.length - 1]] = undefined;
                    }
                    else {
                        diff.applyChange(merge, sess, d);
                    }
                });
                if(differencies.length) debug('Updating session document, because differencies found', differencies, merge);
                if(accessGap > self.setThrottle) debug('Updating session document, because setThrottle expired', accessGap);
                merge.lastAccess = sess.lastAccess;
                if(sess.cookie) {
                    merge.cookie = sess.cookie;
                }
                var doc = {sess: merge};
                doc.expires = expires;
                doc = flat.flatten(doc, {safe: true});
                self.db.merge(sid, doc, function (err) {
                    if (err) return fn(err);
                    return fn();
                });
            }
            else {
                return fn();
            }
        }
        else {
            self.db.get(sid, function (err, doc) {
                if (err) {
                    debug('Session was not found from couchdb, or error occurred', sid);
                    doc = {
                        _id: sid,
                        expires: expires,
                        type: 'connect-session',
                        sess: sess
                    };
                    doc = flat.flatten(doc, {safe: true});
                    self.db.save(doc, function(err) {
                        if(err) return fn(new Error(err));
                        return fn();
                    });
                } else {
                    doc = flat.unflatten(doc, {safe: true});
                    var accessGap = sess.lastAccess - doc.sess.lastAccess;
                    var differencies = diff(doc.sess, sess);

                    differencies = _.filter(differencies, function(d) {
                        var path = d.path.join('.');
                        return ['lastAccess', 'cookie.originalMaxAge', 'cookie._expires', 'cookie.expires', '__connect_couchdb_cache'].indexOf(path) === -1;
                    });
                    // Compare new session to current session, save if different
                    // or setThrottle elapses
                    debug('Differencies from last save: ', differencies);
                    debug('accessGap bigger than setThrottle: ', accessGap > this.setThrottle);
                    var savedSessString = JSON.stringify(doc.sess),
                        currentSessString = JSON.stringify(sess);
                    if (differencies.length || accessGap > this.setThrottle) {
                        doc.expires = expires;
                        doc.sess = sess;
                        debug('Saving session: ', doc.sess);
                        doc = flat.flatten(doc, {safe: true});
                        this.db.save(doc, function(err) {
                            if (err && savedSessString !== currentSessString) {
                                console.error(savedSessString +'!='+ currentSessString);
                                return fn(new Error(err));
                            }
                            return fn();
                        });
                    } else {
                        return fn();
                    }
                }
            }.bind(self));
        }
    }