code: function(path, value, schema) {
      var bsonType = getBSONType(value);
      // if semantic type detection is enabled, the type is the semantic type
      // or the original bson type if no semantic type was detected. If disabled,
      // it is always the bson type.
      var typeName = (options.semanticTypes) ?
        getSemanticType(value, path) || bsonType : bsonType;
      var type = schema[typeName] = _.get(schema, typeName, {
        name: typeName,
        bsonType: bsonType,
        path: path,
        count: 0
      });
      type.count++;
      // recurse into arrays by calling `addToType` for each element
      if (typeName === 'Array') {
        type.types = _.get(type, 'types', {});
        type.lengths = _.get(type, 'lengths', []);
        type.lengths.push(value.length);
        _.each(value, function(v) {
          addToType(path, v, type.types);
        });
  
      // recurse into nested documents by calling `addToField` for all sub-fields
      } else if (typeName === 'Document') {
        type.fields = _.get(type, 'fields', {});
        _.forOwn(value, function(v, k) {
          addToField(path + '.' + k, v, type.fields);
        });
  
      // if the `storeValues` option is enabled, store some example values
      } else if (options.storeValues) {
        type.values = _.get(type, 'values', bsonType === 'String' ?
          new Reservoir(100) : new Reservoir(10000));
        addToValue(type, value);
      }
    }
docs: Takes a field value, determines the correct type, handles recursion into
  nested arrays and documents, and passes the value down to `addToValue`.
  
  @param {String}  path     field path in dot notation
  @param {Any}     value    value of the field
  @param {Object}  schema   the updated schema object